Skip to content

Commit

Permalink
8266536: Provide a variant of os::iso8601_time which works with arbit…
Browse files Browse the repository at this point in the history
…rary timestamps

Reviewed-by: xliu, simonis, ysuenaga
  • Loading branch information
tstuefe committed May 7, 2021
1 parent 71b8ad4 commit 94c6177
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
static const char chunk_file_jfr_ext[] = ".jfr";
static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"
static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS" (note: we just use a subset of the full timestamp)
static fio_fd emergency_fd = invalid_fd;
static const int64_t chunk_file_header_size = 68;
static const size_t chunk_file_extension_length = sizeof chunk_file_jfr_ext - 1;
Expand Down
18 changes: 10 additions & 8 deletions src/hotspot/share/runtime/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,31 +102,33 @@ int os::snprintf(char* buf, size_t len, const char* fmt, ...) {
}

// Fill in buffer with current local time as an ISO-8601 string.
// E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz.
// Returns buffer, or NULL if it failed.
char* os::iso8601_time(char* buffer, size_t buffer_length, bool utc) {
const jlong now = javaTimeMillis();
return os::iso8601_time(now, buffer, buffer_length, utc);
}

// Fill in buffer with an ISO-8601 string corresponding to the given javaTimeMillis value
// E.g., yyyy-mm-ddThh:mm:ss-zzzz.
// Returns buffer, or NULL if it failed.
// This would mostly be a call to
// strftime(...., "%Y-%m-%d" "T" "%H:%M:%S" "%z", ....)
// except that on Windows the %z behaves badly, so we do it ourselves.
// Also, people wanted milliseconds on there,
// and strftime doesn't do milliseconds.
char* os::iso8601_time(char* buffer, size_t buffer_length, bool utc) {
char* os::iso8601_time(jlong milliseconds_since_19700101, char* buffer, size_t buffer_length, bool utc) {
// Output will be of the form "YYYY-MM-DDThh:mm:ss.mmm+zzzz\0"
// 1 2
// 12345678901234567890123456789
// format string: "%04d-%02d-%02dT%02d:%02d:%02d.%03d%c%02d%02d"
static const size_t needed_buffer = 29;

// Sanity check the arguments
if (buffer == NULL) {
assert(false, "NULL buffer");
return NULL;
}
if (buffer_length < needed_buffer) {
if (buffer_length < os::iso8601_timestamp_size) {
assert(false, "buffer_length too small");
return NULL;
}
// Get the current time
jlong milliseconds_since_19700101 = javaTimeMillis();
const int milliseconds_per_microsecond = 1000;
const time_t seconds_since_19700101 =
milliseconds_since_19700101 / milliseconds_per_microsecond;
Expand Down
10 changes: 10 additions & 0 deletions src/hotspot/share/runtime/os.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,16 @@ class os: AllStatic {
static char* local_time_string(char *buf, size_t buflen);
static struct tm* localtime_pd (const time_t* clock, struct tm* res);
static struct tm* gmtime_pd (const time_t* clock, struct tm* res);

// "YYYY-MM-DDThh:mm:ss.mmm+zzzz" incl. terminating zero
static const size_t iso8601_timestamp_size = 29;

// Fill in buffer with an ISO-8601 string corresponding to the given javaTimeMillis value
// E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz.
// Returns buffer, or NULL if it failed.
static char* iso8601_time(jlong milliseconds_since_19700101, char* buffer,
size_t buffer_length, bool utc = false);

// Fill in buffer with current local time as an ISO-8601 string.
// E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz.
// Returns buffer, or NULL if it failed.
Expand Down
54 changes: 54 additions & 0 deletions test/hotspot/gtest/runtime/test_os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,57 @@ TEST_VM(os, dll_address_to_function_and_library_name) {
}
}
}

// Not a regex! Very primitive, just match:
// "d" - digit
// "a" - ascii
// "." - everything
// rest must match
static bool very_simple_string_matcher(const char* pattern, const char* s) {
const size_t lp = strlen(pattern);
const size_t ls = strlen(s);
if (ls < lp) {
return false;
}
for (size_t i = 0; i < lp; i ++) {
switch (pattern[i]) {
case '.': continue;
case 'd': if (!isdigit(s[i])) return false; break;
case 'a': if (!isascii(s[i])) return false; break;
default: if (s[i] != pattern[i]) return false; break;
}
}
return true;
}

TEST_VM(os, iso8601_time) {
char buffer[os::iso8601_timestamp_size + 1]; // + space for canary
buffer[os::iso8601_timestamp_size] = 'X'; // canary
const char* result = NULL;
// YYYY-MM-DDThh:mm:ss.mmm+zzzz
const char* const pattern = "dddd-dd-dd.dd:dd:dd.ddd+dddd";

result = os::iso8601_time(buffer, sizeof(buffer), true);
tty->print_cr("%s", result);
EXPECT_EQ(result, buffer);
EXPECT_TRUE(very_simple_string_matcher(pattern, result));

result = os::iso8601_time(buffer, sizeof(buffer), false);
tty->print_cr("%s", result);
EXPECT_EQ(result, buffer);
EXPECT_TRUE(very_simple_string_matcher(pattern, result));

// Test with explicit timestamps
result = os::iso8601_time(0, buffer, sizeof(buffer), true);
tty->print_cr("%s", result);
EXPECT_EQ(result, buffer);
EXPECT_TRUE(very_simple_string_matcher("1970-01-01.00:00:00.000+dddd", result));

result = os::iso8601_time(17, buffer, sizeof(buffer), true);
tty->print_cr("%s", result);
EXPECT_EQ(result, buffer);
EXPECT_TRUE(very_simple_string_matcher("1970-01-01.00:00:00.017+dddd", result));

// Canary should still be intact
EXPECT_EQ(buffer[os::iso8601_timestamp_size], 'X');
}

1 comment on commit 94c6177

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.