Commit 08f4c7d6 authored by Ondřej Surý's avatar Ondřej Surý Committed by Evan Hunt

Add C11 localtime_r and gmtime_r shims for Windows

On Windows, C11 localtime_r() and gmtime_r() functions are not
available.  While localtime() and gmtime() functions are already thread
safe because they use Thread Local Storage, it's quite ugly to #ifdef
around every localtime_r() and gmtime_r() usage to make the usage also
thread-safe on POSIX platforms.

The commit adds wrappers around Windows localtime_s() and gmtime_s()
functions.

NOTE: The implementation of localtime_s and gmtime_s in Microsoft CRT
are incompatible with the C standard since it has reversed parameter
order and errno_t return type.
parent ec95b84e
Pipeline #36845 passed with stages
in 32 minutes and 13 seconds
......@@ -337,11 +337,7 @@ received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) {
}
printf(";; SERVER: %s(%s)\n", fromtext, query->servname);
time(&tnow);
#if !defined(WIN32)
(void)localtime_r(&tnow, &tmnow);
#else /* if !defined(WIN32) */
tmnow = *localtime(&tnow);
#endif /* if !defined(WIN32) */
#ifdef WIN32
/*
......
......@@ -127,15 +127,16 @@ printtime(dst_key_t *key, int type, const char *tag, bool epoch, FILE *stream) {
} else if (epoch) {
fprintf(stream, "%d\n", (int)when);
} else {
time_t now = (time_t)when;
#ifdef _MSC_VER
struct tm *tm = localtime(&now); /* Thread specific. */
#else
time_t now = when;
struct tm t, *tm = localtime_r(&now, &t);
#endif
unsigned int flen;
char timebuf[80];
if (tm == NULL) {
fprintf(stream, "INVALID\n");
return;
}
flen = strftime(timebuf, sizeof(timebuf),
"%a %b %e %H:%M:%S %Y", tm);
INSIST(flen > 0U && flen < sizeof(timebuf));
......
......@@ -3106,15 +3106,11 @@ writeset(const char *prefix, dns_rdatatype_t type) {
static void
print_time(FILE *fp) {
time_t currenttime = time(NULL);
#ifdef _MSC_VER
struct tm *tm = localtime(&currenttime); /* Thread specific. */
#else
struct tm t, *tm = localtime_r(&currenttime, &t);
#endif
unsigned int flen;
char timebuf[80];
if (outputformat != dns_masterformat_text) {
if (tm == NULL || outputformat != dns_masterformat_text) {
return;
}
......
......@@ -62,6 +62,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <isc/lang.h>
......@@ -277,6 +278,16 @@ end_directory(isc_dir_t *dir) {
}
}
inline struct tm *
gmtime_r(const time_t *clock, struct tm *result) {
errno_t ret = gmtime_s(result, clock);
if (ret != 0) {
errno = ret;
return (NULL);
}
return (result);
}
ISC_LANG_ENDDECLS
#endif /* DNS_GEN_WIN32_H */
......@@ -700,11 +700,7 @@ main(int argc, char **argv) {
}
if (now != -1) {
#ifdef _MSC_VER
struct tm *tm = gmtime(&now); /* Thread specific. */
#else
struct tm t, *tm = gmtime_r(&now, &t);
#endif
if (tm != NULL && tm->tm_year > 104) {
n = snprintf(year, sizeof(year), "-%d",
......
......@@ -2191,14 +2191,10 @@ failure:
static isc_stdtime_t
epoch_to_yyyymmdd(time_t when) {
struct tm *tm;
#if !defined(WIN32)
struct tm tm0;
tm = localtime_r(&when, &tm0);
#else /* if !defined(WIN32) */
tm = localtime(&when);
#endif /* if !defined(WIN32) */
struct tm t, *tm = localtime_r(&when, &t);
if (tm == NULL) {
return (0);
}
return (((tm->tm_year + 1900) * 10000) + ((tm->tm_mon + 1) * 100) +
tm->tm_mday);
}
......
......@@ -12,6 +12,7 @@
#ifndef ISC_TIME_H
#define ISC_TIME_H 1
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <windows.h>
......@@ -19,6 +20,30 @@
#include <isc/lang.h>
#include <isc/types.h>
/***
*** POSIX Shims
***/
inline struct tm *
gmtime_r(const time_t *clock, struct tm *result) {
errno_t ret = gmtime_s(result, clock);
if (ret != 0) {
errno = ret;
return (NULL);
}
return (result);
}
inline struct tm *
localtime_r(const time_t *clock, struct tm *result) {
errno_t ret = localtime_s(result, clock);
if (ret != 0) {
errno = ret;
return (NULL);
}
return (result);
}
/***
*** Intervals
***/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment