[libc] implement CLOCK_BOOTTIME
CLOCK_BOOTTIME is defined, but was not implemented. This lead to issues in
openssh-portable, which was falling back to gettimeofday due to the EINVAL it
received from clock_gettime.
Test: system/test/c/clock-gettime
Bug: 38552
Change-Id: I811b0f5dd32629e4945c5021e75a719a4c5981ba
diff --git a/zircon/system/ulib/c/test/BUILD.gn b/zircon/system/ulib/c/test/BUILD.gn
index 0c7104e..f87f4ce 100644
--- a/zircon/system/ulib/c/test/BUILD.gn
+++ b/zircon/system/ulib/c/test/BUILD.gn
@@ -117,9 +117,21 @@
]
}
+test("clock-gettime") {
+ test_group = "c"
+ sources = [
+ "clock-gettime.cc",
+ ]
+ deps = [
+ "$zx/system/ulib/fdio",
+ "$zx/system/ulib/zx",
+ ]
+}
+
group("test") {
testonly = true
deps = [
+ ":clock-gettime",
":debugdata",
":noop-tests.instrumented",
]
diff --git a/zircon/system/ulib/c/test/clock-gettime.cc b/zircon/system/ulib/c/test/clock-gettime.cc
new file mode 100644
index 0000000..af58a4b
--- /dev/null
+++ b/zircon/system/ulib/c/test/clock-gettime.cc
@@ -0,0 +1,58 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <time.h>
+#include <zircon/assert.h>
+
+void test_monotonics() {
+ // The test strategy here is limited, as we do not have a straightforward
+ // mechanism with which to modify the underlying syscall behavior. We switch
+ // back and forward between calling clock_gettime with CLOCK_MONOTONIC and
+ // CLOCK_BOOTTIME, and assert their relative monotonicity. This test ensures
+ // that these calls succeed, and that time is at least frozen, if not
+ // increasing in a monotonic fashion, with repect to both clock ids.
+
+ struct timespec ts;
+
+ int which = 0;
+ for (int i = 0; i < 100; i++) {
+ struct timespec last = ts;
+
+ switch (which) {
+ case 0:
+ ZX_ASSERT(0 == clock_gettime(CLOCK_MONOTONIC, &ts));
+ break;
+ case 1:
+ ZX_ASSERT(0 == clock_gettime(CLOCK_BOOTTIME, &ts));
+ break;
+ case 2:
+ ZX_ASSERT(0 == clock_gettime(CLOCK_MONOTONIC_RAW, &ts));
+ break;
+ }
+
+ if (ts.tv_sec == last.tv_sec) {
+ ZX_ASSERT_MSG(
+ ts.tv_nsec >= last.tv_nsec,
+ "clock_gettime(CLOCK_{MONOTONIC,BOOTTIME}): %ld < %ld",
+ ts.tv_nsec, last.tv_nsec
+ );
+ } else {
+ ZX_ASSERT_MSG(
+ ts.tv_sec >= last.tv_sec,
+ "clock_gettime(CLOCK_{MONOTONIC,BOOTTIME}): %ld (current) < %ld (last)",
+ ts.tv_sec, last.tv_sec
+ );
+ }
+
+ if (++which % 3 == 0) {
+ which = 0;
+ }
+ }
+}
+
+int main() {
+ test_monotonics();
+ return 0;
+}
diff --git a/zircon/third_party/ulib/musl/src/time/clock_gettime.c b/zircon/third_party/ulib/musl/src/time/clock_gettime.c
index 6d42cc7..882df65 100644
--- a/zircon/third_party/ulib/musl/src/time/clock_gettime.c
+++ b/zircon/third_party/ulib/musl/src/time/clock_gettime.c
@@ -9,6 +9,7 @@
int __clock_gettime(clockid_t clk, struct timespec* ts) {
uint32_t zx_clock;
switch (clk) {
+ case CLOCK_BOOTTIME: // see fxb/38552
case CLOCK_MONOTONIC:
case CLOCK_MONOTONIC_RAW:
zx_clock = ZX_CLOCK_MONOTONIC;