pw_chrono: Adds initial SystemClock support to Pigweed

Adds the initial pw_chrono module to Pigweed with a facade for the
pw::chrono::SystemClock. In adition, the pw_chrono_stl module is
provided with the first STL based backend of said module by using
std::chrono::steady_clock.

Change-Id: Id29f4280aa399a81518f6d13183cf495b2ee72dc
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/23260
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Ewout van Bekkum <ewout@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 75fd40a..f3957e4 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -218,6 +218,7 @@
       "$dir_pw_blob_store",
       "$dir_pw_bytes",
       "$dir_pw_checksum",
+      "$dir_pw_chrono",
       "$dir_pw_cpu_exception",
       "$dir_pw_hdlc_lite",
       "$dir_pw_metric",
@@ -257,6 +258,7 @@
       "$dir_pw_blob_store:tests",
       "$dir_pw_bytes:tests",
       "$dir_pw_checksum:tests",
+      "$dir_pw_chrono:tests",
       "$dir_pw_containers:tests",
       "$dir_pw_cpu_exception_armv7m:tests",
       "$dir_pw_fuzzer:tests",
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index 4ad9ea4..29b0061 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -60,6 +60,8 @@
     "$dir_pw_build:docs",
     "$dir_pw_bytes:docs",
     "$dir_pw_checksum:docs",
+    "$dir_pw_chrono:docs",
+    "$dir_pw_chrono_stl:docs",
     "$dir_pw_cli:docs",
     "$dir_pw_containers:docs",
     "$dir_pw_cpu_exception:docs",
diff --git a/modules.gni b/modules.gni
index b079b63..d7dd1a3 100644
--- a/modules.gni
+++ b/modules.gni
@@ -29,6 +29,8 @@
   dir_pw_build = get_path_info("pw_build", "abspath")
   dir_pw_bytes = get_path_info("pw_bytes", "abspath")
   dir_pw_checksum = get_path_info("pw_checksum", "abspath")
+  dir_pw_chrono = get_path_info("pw_chrono", "abspath")
+  dir_pw_chrono_stl = get_path_info("pw_chrono_stl", "abspath")
   dir_pw_cli = get_path_info("pw_cli", "abspath")
   dir_pw_containers = get_path_info("pw_containers", "abspath")
   dir_pw_cpu_exception = get_path_info("pw_cpu_exception", "abspath")
diff --git a/pw_chrono/BUILD b/pw_chrono/BUILD
new file mode 100644
index 0000000..b13b14f
--- /dev/null
+++ b/pw_chrono/BUILD
@@ -0,0 +1,100 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load(
+    "//pw_build:pigweed.bzl",
+    "pw_cc_library",
+    "pw_cc_test",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+# TODO(pwbug/101): Need to add support for facades/backends to Bazel.
+PW_CHRONO_SYSTEM_CLOCK_BACKEND = "//pw_chrono_stl:system_clock"
+
+pw_cc_library(
+    name = "epoch",
+    hdrs = [
+        "public/pw_chrono/epoch.h",
+    ],
+    includes = ["public"],
+)
+
+pw_cc_library(
+    name = "system_clock_facade",
+    hdrs = [
+        "public/pw_chrono/system_clock.h",
+    ],
+    includes = ["public"],
+    srcs = [
+        "system_clock.cc"
+    ],
+    deps = [
+        ":epoch",
+        PW_CHRONO_SYSTEM_CLOCK_BACKEND + "_headers",
+        "//pw_preprocessor",
+    ],
+)
+
+pw_cc_library(
+    name = "system_clock",
+    deps = [
+        ":system_clock_facade",
+        PW_CHRONO_SYSTEM_CLOCK_BACKEND + "_headers",
+    ],
+)
+
+pw_cc_library(
+    name = "system_clock_backend",
+    deps = [
+       PW_CHRONO_SYSTEM_CLOCK_BACKEND,
+    ],
+)
+
+pw_cc_library(
+    name = "simulated_system_clock",
+    hdrs = [
+        "public/pw_chrono/simulated_system_clock.h",
+    ],
+    deps = [
+        ":system_clock",
+        "//pw_sync:spin_lock",
+    ],
+)
+
+pw_cc_test(
+    name = "simulated_system_clock_test",
+    srcs = [
+        "simulated_system_clock_test.cc",
+    ],
+    deps = [
+        ":simulated_system_clock",
+        "//pw_unit_test",
+    ],
+)
+
+pw_cc_test(
+    name = "system_clock_facade_test",
+    srcs = [
+        "system_clock_facade_test.cc",
+        "system_clock_facade_test_c.c",
+    ],
+    deps = [
+        ":system_clock",
+        "//pw_preprocessor",
+        "//pw_unit_test",
+    ],
+)
diff --git a/pw_chrono/BUILD.gn b/pw_chrono/BUILD.gn
new file mode 100644
index 0000000..9eda0d7
--- /dev/null
+++ b/pw_chrono/BUILD.gn
@@ -0,0 +1,81 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/facade.gni")
+import("$dir_pw_chrono/backend.gni")
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("public_include_path") {
+  include_dirs = [ "public" ]
+  visibility = [ ":*" ]
+}
+
+pw_source_set("epoch") {
+  public = [ "public/pw_chrono/epoch.h" ]
+  public_configs = [ ":public_include_path" ]
+}
+
+pw_facade("system_clock") {
+  backend = pw_chrono_SYSTEM_CLOCK_BACKEND
+  public_configs = [ ":public_include_path" ]
+  public = [ "public/pw_chrono/system_clock.h" ]
+  public_deps = [
+    ":epoch",
+    "$dir_pw_preprocessor",
+  ]
+  sources = [ "system_clock.cc" ]
+}
+
+# Dependency injectable implementation of pw::chrono::SystemClock::Interface.
+pw_source_set("simulated_system_clock") {
+  public_configs = [ ":public_include_path" ]
+  public = [ "public/pw_chrono/simulated_system_clock.h" ]
+  public_deps = [
+    ":system_clock",
+    "$dir_pw_sync:spin_lock",
+  ]
+}
+
+pw_test_group("tests") {
+  tests = [
+    ":simulated_system_clock_test",
+    ":system_clock_facade_test",
+  ]
+}
+
+pw_test("simulated_system_clock_test") {
+  enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
+  sources = [ "simulated_system_clock_test.cc" ]
+  deps = [ ":simulated_system_clock" ]
+}
+
+pw_test("system_clock_facade_test") {
+  enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
+  sources = [
+    "system_clock_facade_test.cc",
+    "system_clock_facade_test_c.c",
+  ]
+  deps = [
+    ":system_clock",
+    "$dir_pw_preprocessor",
+    pw_chrono_SYSTEM_CLOCK_BACKEND,
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [ "docs.rst" ]
+}
diff --git a/pw_chrono/backend.gni b/pw_chrono/backend.gni
new file mode 100644
index 0000000..f5f80e8
--- /dev/null
+++ b/pw_chrono/backend.gni
@@ -0,0 +1,18 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+declare_args() {
+  # Backend for the pw_chrono module's system_clock.
+  pw_chrono_SYSTEM_CLOCK_BACKEND = ""
+}
diff --git a/pw_chrono/docs.rst b/pw_chrono/docs.rst
new file mode 100644
index 0000000..e62aba6
--- /dev/null
+++ b/pw_chrono/docs.rst
@@ -0,0 +1,21 @@
+.. _module-pw_chrono:
+
+---------
+pw_chrono
+---------
+Pigweed's chrono module provides facilities for applications to deal with time,
+leveraging many pieces of STL's the ``std::chrono`` library but with a focus
+on portability for constrained embedded devices and maintaining correctness.
+
+.. warning::
+  This module is under construction, not ready for use, and the documentation
+  is incomplete.
+
+SystemClock facade
+------------------
+The ``pw::chrono::SystemClock`` is meant to serve as the clock used for time
+bound operations such as thread sleeping, waiting on mutexes/semaphores, etc.
+The ``SystemClock`` always uses a signed 64 bit as the underlying type for time
+points and durations. This means users do not have to worry about clock overflow
+risk as long as rational durations and time points as used, i.e. within a range
+of ±292 years.
diff --git a/pw_chrono/public/pw_chrono/epoch.h b/pw_chrono/public/pw_chrono/epoch.h
new file mode 100644
index 0000000..5f0e860
--- /dev/null
+++ b/pw_chrono/public/pw_chrono/epoch.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+namespace pw::chrono {
+
+enum class Epoch {
+  // The epoch is unkown and possibly even undefined in case the clock is not
+  // always enabled and the epoch may reset over time.
+  kUnknown,
+
+  kTimeSinceBoot,
+
+  // Time since 00:00:00 UTC, Thursday, 1 January 1970, including leap seconds.
+  kUtcWallClock,
+
+  // Time since 00:00:00, 6 January 1980 UTC. Leap seconds are not inserted into
+  // GPS. Thus, every time a leap second is inserted into UTC, UTC falls another
+  // second behind GPS.
+  kGpsWallClock,
+
+  // Time since 00:00:00, 1 January 1958, and is offset 10 seconds ahead of UTC
+  // at that date (i.e., its epoch, 1958-01-01 00:00:00 TAI, is 1957-12-31
+  // 23:59:50 UTC). Leap seconds are not inserted into TAI. Thus, every time a
+  // leap second is inserted into UTC, UTC falls another second behind TAI.
+  kTaiWallClock,
+};
+
+}  // namespace pw::chrono
diff --git a/pw_chrono/public/pw_chrono/simulated_system_clock.h b/pw_chrono/public/pw_chrono/simulated_system_clock.h
new file mode 100644
index 0000000..477b34a
--- /dev/null
+++ b/pw_chrono/public/pw_chrono/simulated_system_clock.h
@@ -0,0 +1,70 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#pragma once
+
+#include <mutex>
+
+#include "pw_chrono/system_clock.h"
+#include "pw_sync/spin_lock.h"
+
+namespace pw::chrono {
+
+// A simulated system clock is a concrete virtual SystemClock implementation
+// that does not "tick" on its own. Time is advanced by explicit calls to
+// AdvanceTime() or SetTime() functions. This can be used as stub for testing
+// which can be dependency injected. Be careful when using SetTime() to not
+// violate the is_monotonic requirement, in other words avoid going backwards
+// unless initializing the clock before consumers have a reference to the clock.
+//
+// Example:
+//   SimulatedSystemClock sim_system_clock;
+//
+//   SystemClock::time_point now = sim_system_clock.now();
+//   // now.time_since_epoch.duration() == std::chrono::seconds(0)
+//
+//   sim_system_clock.AdvanceTime(std::chrono::seconds(42));
+//   // now.time_since_epoch.duration() == std::chrono::seconds(42)
+//
+// This code is thread & IRQ safe.
+class SimulatedSystemClock : public VirtualSystemClock {
+ public:
+  SimulatedSystemClock(SystemClock::time_point timestamp =
+                           SystemClock::time_point(SystemClock::duration(0)))
+      : current_timestamp_(timestamp) {}
+
+  void AdvanceTime(SystemClock::duration duration) {
+    std::lock_guard lock(spin_lock_);
+    current_timestamp_ += duration;
+  }
+
+  // WARNING: Use of this function may violate the is_monotonic clock attribute.
+  void SetTime(SystemClock::time_point timestamp) {
+    std::lock_guard lock(spin_lock_);
+    current_timestamp_ = timestamp;
+  }
+
+  SystemClock::time_point now() override {
+    std::lock_guard lock(spin_lock_);
+    return current_timestamp_;
+  };
+
+ private:
+  // In theory atomics could be used if 64bit atomics are supported, however
+  // performance of this test object shouldn't matter.
+  sync::SpinLock spin_lock_;
+  SystemClock::time_point current_timestamp_;
+};
+
+}  // namespace pw::chrono
diff --git a/pw_chrono/public/pw_chrono/system_clock.h b/pw_chrono/public/pw_chrono/system_clock.h
new file mode 100644
index 0000000..82e5fbb
--- /dev/null
+++ b/pw_chrono/public/pw_chrono/system_clock.h
@@ -0,0 +1,171 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "pw_preprocessor/util.h"
+
+#ifdef __cplusplus
+
+#include <chrono>
+
+// The backend implements this header to provide the following SystemClock
+// parameters, for more detail on the parameters see the SystemClock usage of
+// them below:
+//   std::ratio<> typed pw::chrono::backend::SystemClockPeriodSecondsRatio type
+//   constexpr pw::chrono::Epoch pw::chrono::backend::kSystemClockEpoch;
+//   constexpr bool pw::chrono::backend::kSystemClockFreeRunning;
+//   constexpr bool pw::chrono::backend::kSystemClockNmiSafe;
+#include "pw_chrono_backend/system_clock_config.h"
+
+namespace pw::chrono {
+namespace backend {
+
+// The ARM AEBI does not permit the opaque 'time_point' to be passed via
+// registers, ergo the underlying fundamental type is forward declared.
+// A SystemCLock tick has the units of one SystemClock::period duration.
+// This must be thread and IRQ safe and provided by the backend.
+int64_t GetSystemClockTickCount();
+
+}  // namespace backend
+
+// The SystemClock represents an unsteady, monotonic clock.
+//
+// The epoch of this clock is unspecified and may not be related to wall time
+// (for example, it can be time since boot). The time between ticks of this
+// clock may vary due to sleep modes and potential interrupt handling.
+// SystemClock meets the requirements of C++'s TrivialClock and Pigweed's
+// PigweedClock.
+//
+// Example:
+//
+//   SystemClock::time_point before = SystemClock::now();
+//   TakesALongTime();
+//   SystemClock::duration time_taken = SystemClock::now() - before;
+//   bool took_way_too_long = false;
+//   if (time_taken > std::chrono::seconds(42)) {
+//     took_way_too_long = true;
+//   }
+//
+// This code is thread & IRQ safe, it may be NMI safe depending on is_nmi_safe.
+struct SystemClock {
+  using rep = int64_t;
+  // The period must be provided by the backend.
+  using period = backend::SystemClockPeriodSecondsRatio;
+  using duration = std::chrono::duration<rep, period>;
+  using time_point = std::chrono::time_point<SystemClock>;
+  // The epoch m ust be provided by the backend.
+  static constexpr Epoch epoch = backend::kSystemClockEpoch;
+
+  // The time points of this clock cannot decrease, however the time between
+  // ticks of this clock may slightly vary due to sleep modes. The duration
+  // during sleep may be ignored or backfilled with another clock.
+  static constexpr bool is_monotonic = true;
+  static constexpr bool is_steady = false;
+
+  // The now() function may not move forward while in a critical section or
+  // interrupt. This must be provided by the backend.
+  static constexpr bool is_free_running = backend::kSystemClockFreeRunning;
+
+  // The clock must stop while in halting debug mode.
+  static constexpr bool is_stopped_in_halting_debug_mode = true;
+
+  // The now() function can be invoked at any time.
+  static constexpr bool is_always_enabled = true;
+
+  // The now() function may work in non-masking interrupts, depending on the
+  // backend. This must be provided by the backend.
+  static constexpr bool is_nmi_safe = backend::kSystemClockNmiSafe;
+
+  // This is thread and IRQ safe. This must be provided by the backend.
+  static time_point now() {
+    return time_point(duration(backend::GetSystemClockTickCount()));
+  }
+};
+
+// An abstract interface representing a SystemClock.
+//
+// This interface allows decoupling code that uses time from the code that
+// creates a point in time. You can use this to your advantage by injecting
+// Clocks into interfaces rather than having implementations call
+// SystemClock::now() directly. However, this comes at a cost of a vtable per
+// implementation and more importantly passing and maintaining references to the
+// VirtualSystemCLock for all of the users.
+//
+// The VirtualSystemClock::RealClock() function returns a reference to the
+// real global SystemClock.
+//
+// Example:
+//
+//  void DoFoo(VirtualSystemClock& system_clock) {
+//    SystemClock::time_point now = clock.now();
+//    // ... Code which consumes now.
+//  }
+//
+//  // Production code:
+//  DoFoo(VirtualSystemCLock::RealClock);
+//
+//  // Test code:
+//  MockClock test_clock();
+//  DoFoo(test_clock);
+//
+// This interface is thread and IRQ safe.
+class VirtualSystemClock {
+ public:
+  // Returns a reference to the real system clock to aid instantiation.
+  static VirtualSystemClock& RealClock();
+
+  virtual ~VirtualSystemClock() = default;
+  virtual SystemClock::time_point now() = 0;
+};
+
+}  // namespace pw::chrono
+
+// The backend can opt to include an inlined implementation of the following:
+//   int64_t GetSystemClockTickCount();
+#if __has_include("pw_chrono_backend/system_clock_inline.h")
+#include "pw_chrono_backend/system_clock_inline.h"
+#endif
+
+#endif  // __cplusplus
+
+PW_EXTERN_C_START
+
+typedef int64_t pw_chrono_SystemClock_TickCount;
+typedef struct {
+  pw_chrono_SystemClock_TickCount ticks_since_epoch;
+} pw_chrono_SystemClock_TimePoint;
+typedef int64_t pw_chrono_SystemClock_Nanoseconds;
+
+// Returns the current time, see SystemClock::now() for more detail.
+pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_Now();
+
+// Returns the change in time between the current_time - last_time.
+pw_chrono_SystemClock_TickCount pw_chrono_SystemClock_TimeDelta(
+    pw_chrono_SystemClock_TimePoint last_time,
+    pw_chrono_SystemClock_TimePoint current_time);
+
+// For lossless time unit conversion, the seconds per tick ratio that is
+// numerator/denominator should be used.
+int32_t pw_chrono_SystemClock_PeriodSeconds_Numerator();
+int32_t pw_chrono_SystemClock_PeriodSeconds_Denominator();
+
+// Warning, this may be lossy due to the use of std::chrono::duration_cast,
+// rounding towards zero.
+pw_chrono_SystemClock_Nanoseconds pw_chrono_SystemClock_TickCountToNsTruncate(
+    pw_chrono_SystemClock_TickCount ticks);
+
+PW_EXTERN_C_END
diff --git a/pw_chrono/simulated_system_clock_test.cc b/pw_chrono/simulated_system_clock_test.cc
new file mode 100644
index 0000000..5102a99
--- /dev/null
+++ b/pw_chrono/simulated_system_clock_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_chrono/simulated_system_clock.h"
+
+#include "gtest/gtest.h"
+
+namespace pw::chrono {
+namespace {
+
+constexpr auto kArbitraryDuration = std::chrono::hours(42);
+// We can't control the SystemClock's period configuration, so just in case
+// 42 hours cannot be accurately expressed in integer ticks, round the
+// duration w/ duration_cast.
+constexpr auto kRoundedArbitraryDuration =
+    std::chrono::duration_cast<SystemClock::duration>(kArbitraryDuration);
+
+TEST(SimulatedSystemClock, InitialTime) {
+  SimulatedSystemClock clock;
+
+  EXPECT_EQ(SystemClock::time_point(SystemClock::duration(0)), clock.now());
+}
+
+TEST(SimulatedSystemClock, SetTime) {
+  SimulatedSystemClock clock;
+
+  clock.SetTime(pw::chrono::SystemClock::time_point(kRoundedArbitraryDuration));
+  EXPECT_EQ(kRoundedArbitraryDuration, clock.now().time_since_epoch());
+}
+
+TEST(SimulatedSystemClock, AdvanceTime) {
+  SimulatedSystemClock clock;
+
+  const SystemClock::time_point before_timestamp = clock.now();
+  clock.AdvanceTime(kRoundedArbitraryDuration);
+  const SystemClock::time_point after_timestamp = clock.now();
+
+  EXPECT_EQ(kRoundedArbitraryDuration, clock.now().time_since_epoch());
+  EXPECT_EQ(kRoundedArbitraryDuration, after_timestamp - before_timestamp);
+}
+
+}  // namespace
+}  // namespace pw::chrono
diff --git a/pw_chrono/system_clock.cc b/pw_chrono/system_clock.cc
new file mode 100644
index 0000000..cbf8d45
--- /dev/null
+++ b/pw_chrono/system_clock.cc
@@ -0,0 +1,59 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_chrono/system_clock.h"
+
+namespace pw::chrono {
+namespace {
+
+class RealSystemClock final : public VirtualSystemClock {
+ public:
+  SystemClock::time_point now() final { return SystemClock::now(); }
+};
+RealSystemClock real_system_clock;
+
+}  // namespace
+
+VirtualSystemClock& VirtualSystemClock::RealClock() {
+  return real_system_clock;
+}
+
+}  // namespace pw::chrono
+
+extern "C" pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_Now() {
+  return {.ticks_since_epoch =
+              pw::chrono::SystemClock::now().time_since_epoch().count()};
+}
+
+extern "C" pw_chrono_SystemClock_TickCount pw_chrono_SystemClock_TimeDelta(
+    pw_chrono_SystemClock_TimePoint last_time,
+    pw_chrono_SystemClock_TimePoint current_time) {
+  return current_time.ticks_since_epoch - last_time.ticks_since_epoch;
+}
+
+extern "C" int32_t pw_chrono_SystemClock_PeriodSeconds_Numerator() {
+  return pw::chrono::SystemClock::period::num;
+}
+
+extern "C" int32_t pw_chrono_SystemClock_PeriodSeconds_Denominator() {
+  return pw::chrono::SystemClock::period::den;
+}
+
+extern "C" pw_chrono_SystemClock_Nanoseconds
+pw_chrono_SystemClock_TickCountToNsTruncate(
+    pw_chrono_SystemClock_TickCount ticks) {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             pw::chrono::SystemClock::duration(ticks))
+      .count();
+}
diff --git a/pw_chrono/system_clock_facade_test.cc b/pw_chrono/system_clock_facade_test.cc
new file mode 100644
index 0000000..1d60b11
--- /dev/null
+++ b/pw_chrono/system_clock_facade_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <chrono>
+
+#include "gtest/gtest.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_preprocessor/util.h"
+
+namespace pw::chrono {
+namespace {
+
+extern "C" {
+
+// Functions defined in system_clock_facade_test_c.c which call the API from C.
+pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_CallNow();
+pw_chrono_SystemClock_TickCount pw_chrono_SystemClock_CallTimeDelta(
+    pw_chrono_SystemClock_TimePoint last_time,
+    pw_chrono_SystemClock_TimePoint current_time);
+
+int32_t pw_chrono_SystemClock_PeriodSeconds_CallNumerator();
+int32_t pw_chrono_SystemClock_PeriodSeconds_CallDenominator();
+
+pw_chrono_SystemClock_Nanoseconds
+pw_chrono_SystemClock_CallTickCountToNsTruncate(
+    pw_chrono_SystemClock_TickCount ticks);
+
+}  // extern "C"
+
+// While testing that the clock ticks (i.e. moves forward) we want to ensure a
+// failure can be reported instead of deadlocking the test until it passes.
+// Given that there isn't really a good heuristic for this we instead make some
+// wild assumptions to bound the maximum busy loop iterations.
+// - Assume our clock is < 6Ghz
+// - Assume we can check the clock in a single cycle
+// - Wait for up to 1/10th of a second @ 6Ghz, this may be a long period on a
+//   slower (i.e. real) machine.
+constexpr uint64_t kMaxIterations = 6'000'000'000 / 10;
+
+TEST(SystemClock, Now) {
+  const SystemClock::time_point start_time = SystemClock::now();
+  // Verify the clock moves forward.
+  bool clock_moved_forward = false;
+  for (uint64_t i = 0; i < kMaxIterations; ++i) {
+    if (SystemClock::now() > start_time) {
+      clock_moved_forward = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(clock_moved_forward);
+}
+
+TEST(VirtualSystemClock, Now) {
+  auto& clock = VirtualSystemClock::RealClock();
+  const SystemClock::time_point start_time = clock.now();
+  // Verify the clock moves forward.
+  bool clock_moved_forward = false;
+  for (uint64_t i = 0; i < kMaxIterations; ++i) {
+    if (clock.now() > start_time) {
+      clock_moved_forward = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(clock_moved_forward);
+}
+
+TEST(SystemClock, NowInC) {
+  const pw_chrono_SystemClock_TimePoint start_time =
+      pw_chrono_SystemClock_CallNow();
+  // Verify the clock moves forward.
+  bool clock_moved_forward = false;
+  for (uint64_t i = 0; i < kMaxIterations; ++i) {
+    if (pw_chrono_SystemClock_CallNow().ticks_since_epoch >
+        start_time.ticks_since_epoch) {
+      clock_moved_forward = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(clock_moved_forward);
+}
+
+TEST(SystemClock, TimeDeltaInC) {
+  const pw_chrono_SystemClock_TimePoint first = pw_chrono_SystemClock_CallNow();
+  const pw_chrono_SystemClock_TimePoint last = pw_chrono_SystemClock_CallNow();
+  static_assert(SystemClock::is_monotonic);
+  EXPECT_GE(0, pw_chrono_SystemClock_CallTimeDelta(last, first));
+}
+
+TEST(SystemClock, PeriodRatioInC) {
+  EXPECT_EQ(SystemClock::period::num,
+            pw_chrono_SystemClock_PeriodSeconds_CallNumerator());
+  EXPECT_EQ(SystemClock::period::den,
+            pw_chrono_SystemClock_PeriodSeconds_CallDenominator());
+}
+
+TEST(SystemClock, DurationCastInC) {
+  static constexpr auto kArbitraryPeriod = std::chrono::hours(42);
+  // We can't control the SystemClock's period configuration, so just in case
+  // 42 hours cannot be accurately expressed in integer ticks, round the
+  // duration w/ duration_cast.
+  static constexpr auto kRoundedArbitraryDuration =
+      std::chrono::duration_cast<SystemClock::duration>(kArbitraryPeriod);
+  EXPECT_EQ(std::chrono::duration_cast<std::chrono::nanoseconds>(
+                kRoundedArbitraryDuration)
+                .count(),
+            pw_chrono_SystemClock_CallTickCountToNsTruncate(
+                kRoundedArbitraryDuration.count()));
+}
+
+}  // namespace
+}  // namespace pw::chrono
diff --git a/pw_chrono/system_clock_facade_test_c.c b/pw_chrono/system_clock_facade_test_c.c
new file mode 100644
index 0000000..1ae3456
--- /dev/null
+++ b/pw_chrono/system_clock_facade_test_c.c
@@ -0,0 +1,42 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// These tests call the pw_chrono module system_clock API from C. The return
+// values are checked in the main C++ tests.
+
+#include "pw_chrono/system_clock.h"
+
+pw_chrono_SystemClock_TimePoint pw_chrono_SystemClock_CallNow() {
+  return pw_chrono_SystemClock_Now();
+}
+
+pw_chrono_SystemClock_TickCount pw_chrono_SystemClock_CallTimeDelta(
+    pw_chrono_SystemClock_TimePoint last_time,
+    pw_chrono_SystemClock_TimePoint current_time) {
+  return pw_chrono_SystemClock_TimeDelta(last_time, current_time);
+}
+
+int32_t pw_chrono_SystemClock_PeriodSeconds_CallNumerator() {
+  return pw_chrono_SystemClock_PeriodSeconds_Numerator();
+}
+
+int32_t pw_chrono_SystemClock_PeriodSeconds_CallDenominator() {
+  return pw_chrono_SystemClock_PeriodSeconds_Denominator();
+}
+
+pw_chrono_SystemClock_Nanoseconds
+pw_chrono_SystemClock_CallTickCountToNsTruncate(
+    pw_chrono_SystemClock_TickCount ticks) {
+  return pw_chrono_SystemClock_TickCountToNsTruncate(ticks);
+}
diff --git a/pw_chrono_stl/BUILD b/pw_chrono_stl/BUILD
new file mode 100644
index 0000000..e1abacf
--- /dev/null
+++ b/pw_chrono_stl/BUILD
@@ -0,0 +1,47 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load(
+    "//pw_build:pigweed.bzl",
+    "pw_cc_library",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])  # Apache License 2.0
+
+pw_cc_library(
+    name = "system_clock_headers",
+    hdrs = [
+        "public/pw_chrono_stl/system_clock_config.h",
+        "public/pw_chrono_stl/system_clock_inline.h",
+        "public_overrides/pw_chrono_backend/system_clock_config.h",
+        "public_overrides/pw_chrono_backend/system_clock_inline.h",
+    ],
+    includes = [
+        "public",
+        "public_overrides",
+    ],
+    deps = [
+        "//pw_chrono:epoch",
+    ],
+)
+
+pw_cc_library(
+    name = "system_clock",
+    deps = [
+        ":system_clock_headers",
+        "//pw_chrono:system_clock_facade",
+    ],
+)
diff --git a/pw_chrono_stl/BUILD.gn b/pw_chrono_stl/BUILD.gn
new file mode 100644
index 0000000..948738d
--- /dev/null
+++ b/pw_chrono_stl/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_docgen/docs.gni")
+
+config("public_include_path") {
+  include_dirs = [ "public" ]
+  visibility = [ ":*" ]
+}
+
+config("backend_config") {
+  include_dirs = [ "public_overrides" ]
+  visibility = [ ":*" ]
+}
+
+# This target provides the backend for pw::chrono::SystemClock.
+pw_source_set("system_clock") {
+  public_configs = [
+    ":public_include_path",
+    ":backend_config",
+  ]
+  public = [
+    "public/pw_chrono_stl/system_clock_config.h",
+    "public/pw_chrono_stl/system_clock_inline.h",
+    "public_overrides/pw_chrono_backend/system_clock_config.h",
+    "public_overrides/pw_chrono_backend/system_clock_inline.h",
+  ]
+  public_deps = [
+    "$dir_pw_chrono:epoch",
+    "$dir_pw_chrono:system_clock.facade",
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [ "docs.rst" ]
+}
diff --git a/pw_chrono_stl/docs.rst b/pw_chrono_stl/docs.rst
new file mode 100644
index 0000000..8160deb
--- /dev/null
+++ b/pw_chrono_stl/docs.rst
@@ -0,0 +1,26 @@
+.. _module-pw_chrono_stl:
+
+-------------
+pw_chrono_stl
+-------------
+``pw_chrono_stl`` is a collection of ``pw_chrono`` backends that are implemented
+using STL's ``std::chrono`` library.
+
+.. warning::
+  This module is under construction, not ready for use, and the documentation
+  is incomplete.
+
+SystemClock backend
+-------------------
+The STL based ``system_clock`` backend implements the ``pw_chrono:system_clock``
+facade by using the ``std::chrono::steady_clock``. Note that the
+``std::chrono::system_clock`` cannot be used as this is not always a monotonic
+clock source.
+
+See the documentation for ``pw_chrono`` for further details.
+
+Build targets
+-------------
+The GN build for ``pw_chrono_stl`` has one target: ``system_clock``.
+The ``system_clock`` target provides the ``pw_chrono_stl/system_clock.h`` header
+and the backend for the ``pw_chrono:system_clock``.
diff --git a/pw_chrono_stl/public/pw_chrono_stl/system_clock_config.h b/pw_chrono_stl/public/pw_chrono_stl/system_clock_config.h
new file mode 100644
index 0000000..05b1c71
--- /dev/null
+++ b/pw_chrono_stl/public/pw_chrono_stl/system_clock_config.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <chrono>
+
+#include "pw_chrono/epoch.h"
+
+namespace pw::chrono::backend {
+
+// Provide the native std::chrono::steady_clock period.
+using SystemClockPeriodSecondsRatio = std::chrono::steady_clock::period;
+
+// The std::chrono::steady_clock does not have a defined epoch.
+constexpr inline Epoch kSystemClockEpoch = pw::chrono::Epoch::kUnknown;
+
+// The std::chrono::steady_clock can be used by signal handlers.
+constexpr inline bool kSystemClockNmiSafe = true;
+
+// The std::chrono::steady_clock ticks while in a signal handler.
+constexpr inline bool kSystemClockFreeRunning = true;
+
+}  // namespace pw::chrono::backend
diff --git a/pw_chrono_stl/public/pw_chrono_stl/system_clock_inline.h b/pw_chrono_stl/public/pw_chrono_stl/system_clock_inline.h
new file mode 100644
index 0000000..9fa0d5e
--- /dev/null
+++ b/pw_chrono_stl/public/pw_chrono_stl/system_clock_inline.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <chrono>
+
+#include "pw_chrono/system_clock.h"
+
+namespace pw::chrono::backend {
+
+inline int64_t GetSystemClockTickCount() {
+  // Note that no conversion is necessary since the steady_clock's period and
+  // epoch are directly used.
+  return std::chrono::steady_clock::now().time_since_epoch().count();
+}
+
+}  // namespace pw::chrono::backend
diff --git a/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_config.h b/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_config.h
new file mode 100644
index 0000000..91c7ed8
--- /dev/null
+++ b/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_config.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// This override header includes the main tokenized logging header and defines
+// the PW_LOG macro as the tokenized logging macro.
+#pragma once
+
+#include "pw_chrono_stl/system_clock_config.h"
diff --git a/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_inline.h b/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_inline.h
new file mode 100644
index 0000000..eac3f56
--- /dev/null
+++ b/pw_chrono_stl/public_overrides/pw_chrono_backend/system_clock_inline.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// This override header includes the main tokenized logging header and defines
+// the PW_LOG macro as the tokenized logging macro.
+#pragma once
+
+#include "pw_chrono_stl/system_clock_inline.h"
diff --git a/targets/host/target_toolchains.gni b/targets/host/target_toolchains.gni
index 73c61c0..c757915 100644
--- a/targets/host/target_toolchains.gni
+++ b/targets/host/target_toolchains.gni
@@ -41,6 +41,9 @@
   # Tokenizer trace time.
   pw_trace_tokenizer_time = "$dir_pw_trace_tokenized:host_trace_time"
 
+  # Configure backend for pw_chrono's system_clock facade.
+  pw_chrono_SYSTEM_CLOCK_BACKEND = "$dir_pw_chrono_stl:system_clock"
+
   # Specify builtin GN variables.
   current_os = host_os
   current_cpu = host_cpu