pw_sync: Adds initial SpinLock primitive

Adds the first synchronization primitive to Pigweed: the
pw::sync::SpinLock with integrated local interrupt
masking.

This also provides the first backend for the SpinLock facade
backed by an STL implementation. Note that signals are considered
"NMIs" while spin locks are only supported up to IRQs, ergo no
local interrupt/signal masking is done in the STL implementation.

Change-Id: I34204835c55e54597077d40665f61715964803f9
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/25802
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 6b5b248..75fd40a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -229,6 +229,7 @@
       "$dir_pw_status",
       "$dir_pw_stream",
       "$dir_pw_string",
+      "$dir_pw_sync",
       "$dir_pw_sys_io",
       "$dir_pw_trace",
       "$dir_pw_unit_test",
@@ -280,6 +281,7 @@
       "$dir_pw_status:tests",
       "$dir_pw_stream:tests",
       "$dir_pw_string:tests",
+      "$dir_pw_sync:tests",
       "$dir_pw_tokenizer:tests",
       "$dir_pw_trace:tests",
       "$dir_pw_trace_tokenized:tests",
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index 034587b..6f38d3c 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -94,6 +94,8 @@
     "$dir_pw_status:docs",
     "$dir_pw_stream:docs",
     "$dir_pw_string:docs",
+    "$dir_pw_sync:docs",
+    "$dir_pw_sync_stl:docs",
     "$dir_pw_sys_io:docs",
     "$dir_pw_sys_io_arduino:docs",
     "$dir_pw_sys_io_baremetal_stm32f429:docs",
diff --git a/modules.gni b/modules.gni
index e71cfb2..2576da3 100644
--- a/modules.gni
+++ b/modules.gni
@@ -66,6 +66,8 @@
   dir_pw_status = get_path_info("pw_status", "abspath")
   dir_pw_stream = get_path_info("pw_stream", "abspath")
   dir_pw_string = get_path_info("pw_string", "abspath")
+  dir_pw_sync = get_path_info("pw_sync", "abspath")
+  dir_pw_sync_stl = get_path_info("pw_sync_stl", "abspath")
   dir_pw_sys_io = get_path_info("pw_sys_io", "abspath")
   dir_pw_sys_io_baremetal_lm3s6965evb =
       get_path_info("pw_sys_io_baremetal_lm3s6965evb", "abspath")
diff --git a/pw_sync/BUILD b/pw_sync/BUILD
new file mode 100644
index 0000000..ceb60c6
--- /dev/null
+++ b/pw_sync/BUILD
@@ -0,0 +1,77 @@
+# 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_SYNC_SPIN_LOCK_BACKEND = "//pw_sync_stl:spin_lock"
+
+pw_cc_library(
+    name = "spin_lock_facade",
+    hdrs = [
+        "public/pw_sync/spin_lock.h",
+    ],
+    includes = ["public"],
+    srcs = [
+        "spin_lock.cc"
+    ],
+    deps = [
+        PW_SYNC_SPIN_LOCK_BACKEND + "_headers",
+        "//pw_preprocessor",
+    ],
+)
+
+pw_cc_library(
+    name = "spin_lock",
+    deps = [
+        ":spin_lock_facade",
+        PW_SYNC_SPIN_LOCK_BACKEND + "_headers",
+    ],
+)
+
+pw_cc_library(
+    name = "spin_lock_backend",
+    deps = [
+       PW_SYNC_SPIN_LOCK_BACKEND,
+    ],
+)
+
+pw_cc_library(
+    name = "yield_core",
+    hdrs = [
+        "public/pw_sync/yield_core.h",
+    ],
+    includes = ["public"],
+)
+
+pw_cc_test(
+    name = "spin_lock_facade_test",
+    srcs = [
+        "spin_lock_facade_test.cc",
+        "spin_lock_facade_test_c.c",
+    ],
+    deps = [
+        ":spin_lock",
+        "//pw_preprocessor",
+        "//pw_unit_test",
+    ],
+)
diff --git a/pw_sync/BUILD.gn b/pw_sync/BUILD.gn
new file mode 100644
index 0000000..cf292b8
--- /dev/null
+++ b/pw_sync/BUILD.gn
@@ -0,0 +1,64 @@
+# 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_build/target_types.gni")
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+declare_args() {
+  # Backend for the pw_sync module's spin lock.
+  pw_sync_SPIN_LOCK_BACKEND = ""
+}
+
+config("public_include_path") {
+  include_dirs = [ "public" ]
+  visibility = [ ":*" ]
+}
+
+pw_facade("spin_lock") {
+  backend = pw_sync_SPIN_LOCK_BACKEND
+  public_configs = [ ":public_include_path" ]
+  public = [ "public/pw_sync/spin_lock.h" ]
+  public_deps = [ "$dir_pw_preprocessor" ]
+  sources = [ "spin_lock.cc" ]
+}
+
+pw_test_group("tests") {
+  tests = [ ":spin_lock_facade_test" ]
+}
+
+pw_source_set("yield_core") {
+  public = [ "public/pw_sync/yield_core.h" ]
+  public_configs = [ ":public_include_path" ]
+}
+
+pw_test("spin_lock_facade_test") {
+  enable_if = pw_sync_SPIN_LOCK_BACKEND != ""
+  sources = [
+    "spin_lock_facade_test.cc",
+    "spin_lock_facade_test_c.c",
+  ]
+  deps = [
+    ":spin_lock",
+    "$dir_pw_preprocessor",
+    pw_sync_SPIN_LOCK_BACKEND,
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [ "docs.rst" ]
+}
diff --git a/pw_sync/docs.rst b/pw_sync/docs.rst
new file mode 100644
index 0000000..1dfe23f
--- /dev/null
+++ b/pw_sync/docs.rst
@@ -0,0 +1,8 @@
+.. _module-pw_sync:
+
+-------
+pw_sync
+-------
+This is a synchronization module for Pigweed. It is not ready for use, and
+is under construction.
+
diff --git a/pw_sync/public/pw_sync/spin_lock.h b/pw_sync/public/pw_sync/spin_lock.h
new file mode 100644
index 0000000..fdce5e3
--- /dev/null
+++ b/pw_sync/public/pw_sync/spin_lock.h
@@ -0,0 +1,93 @@
+// 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 <stdbool.h>
+
+#include "pw_preprocessor/util.h"
+
+#ifdef __cplusplus
+
+#include "pw_sync_backend/spin_lock_native.h"
+
+namespace pw::sync {
+
+// The SpinLock is a synchronization primitive that can be used to protect
+// shared data from being simultaneously accessed by multiple threads and/or
+// IRQs as a targeted global lock (except for NMIs).
+// It offers exclusive, non-recursive ownership semantics where IRQs up to a
+// backend defined level of "NMIs" will be masked to solve priority-inversion.
+//
+// NOTE: This SpinLock relies on built-in local interrupt masking to make it IRQ
+// safe without requiring the caller to mask interrupts manually when using this
+// primitive.
+//
+// Unlike global interrupt locks, this also works safely and efficiently on SMP
+// systems. This entire API is IRQ safe.
+//
+// WARNING: Code that holds a specific SpinLock must not try to re-acquire it
+// or it will deadlock. However, it is okay to nest distinct spinlocks.
+//
+// WARNING: In order to support global statically constructed SpinLocks, the
+// backend MUST ensure that any initialization required in your environment
+// prior to the creation and/or initialization of the native semaphore
+// (e.g. kernel initialization), is done before or during the invocation of the
+// global static C++ constructors.
+class SpinLock {
+ public:
+  using native_handle_type = backend::NativeSpinLockHandle;
+
+  SpinLock();
+  ~SpinLock() = default;
+  SpinLock(const SpinLock&) = delete;
+  SpinLock(SpinLock&&) = delete;
+  SpinLock& operator=(const SpinLock&) = delete;
+  SpinLock& operator=(SpinLock&&) = delete;
+
+  // Locks the spinlock, blocking indefinitely. Failures are fatal.
+  void lock();
+
+  // Attempts to lock the spinlock in a non-blocking manner.
+  // Returns true if the spinlock was successfully acquired.
+  bool try_lock();
+
+  // Unlocks the spinlock. Failures are fatal.
+  void unlock();
+
+  native_handle_type native_handle();
+
+ private:
+  // This may be a wrapper around a native type with additional members.
+  backend::NativeSpinLock native_type_;
+};
+
+}  // namespace pw::sync
+
+#include "pw_sync_backend/spin_lock_inline.h"
+
+using pw_sync_SpinLock = pw::sync::SpinLock;
+
+#else  // !defined(__cplusplus)
+
+typedef struct pw_sync_SpinLock pw_sync_SpinLock;
+
+#endif  // __cplusplus
+
+PW_EXTERN_C_START
+
+void pw_sync_SpinLock_Lock(pw_sync_SpinLock* spin_lock);
+bool pw_sync_SpinLock_TryLock(pw_sync_SpinLock* spin_lock);
+void pw_sync_SpinLock_Unlock(pw_sync_SpinLock* spin_lock);
+
+PW_EXTERN_C_END
diff --git a/pw_sync/public/pw_sync/yield_core.h b/pw_sync/public/pw_sync/yield_core.h
new file mode 100644
index 0000000..4a04e2b
--- /dev/null
+++ b/pw_sync/public/pw_sync/yield_core.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
+
+// PW_SYNC_YIELD_CORE_FOR_SMT provides the architecture specific processor hint
+// to allow the processor to yield in the case of SMT.
+#if defined(__x86_64__) || defined(__i386__)
+#include <immintrin.h>
+#define PW_SYNC_YIELD_CORE_FOR_SMT() _mm_pause()
+
+#elif defined(__aarch64__) || defined(__arm__)
+#define PW_SYNC_YIELD_CORE_FOR_SMT() asm volatile("yield" ::: "memory")
+
+#else
+#error "No processor yield implementation for this architecture."
+
+#endif  // PW_SYNC_YIELD_CORE_FOR_SMT
diff --git a/pw_sync/spin_lock.cc b/pw_sync/spin_lock.cc
new file mode 100644
index 0000000..86de70b
--- /dev/null
+++ b/pw_sync/spin_lock.cc
@@ -0,0 +1,27 @@
+// 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_sync/spin_lock.h"
+
+extern "C" void pw_sync_SpinLock_Lock(pw_sync_SpinLock* spin_lock) {
+  spin_lock->lock();
+}
+
+extern "C" bool pw_sync_SpinLock_TryLock(pw_sync_SpinLock* spin_lock) {
+  return spin_lock->try_lock();
+}
+
+extern "C" void pw_sync_SpinLock_Unlock(pw_sync_SpinLock* spin_lock) {
+  spin_lock->unlock();
+}
diff --git a/pw_sync/spin_lock_facade_test.cc b/pw_sync/spin_lock_facade_test.cc
new file mode 100644
index 0000000..c115bd9
--- /dev/null
+++ b/pw_sync/spin_lock_facade_test.cc
@@ -0,0 +1,67 @@
+// 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 "gtest/gtest.h"
+#include "pw_sync/spin_lock.h"
+
+namespace pw::sync {
+namespace {
+
+extern "C" {
+
+// Functions defined in spin_lock_facade_test_c.c which call the API from C.
+void pw_sync_SpinLock_CallLock(pw_sync_SpinLock* spin_lock);
+bool pw_sync_SpinLock_CallTryLock(pw_sync_SpinLock* spin_lock);
+void pw_sync_SpinLock_CallUnlock(pw_sync_SpinLock* spin_lock);
+
+}  // extern "C"
+
+TEST(SpinLock, LockUnlock) {
+  pw::sync::SpinLock spin_lock;
+  spin_lock.lock();
+  spin_lock.unlock();
+}
+
+SpinLock static_spin_lock;
+TEST(SpinLock, LockUnlockStatic) {
+  static_spin_lock.lock();
+  // Ensure it fails to lock when already held.
+  EXPECT_FALSE(static_spin_lock.try_lock());
+  static_spin_lock.unlock();
+}
+
+TEST(SpinLock, TryLockUnlock) {
+  pw::sync::SpinLock spin_lock;
+  ASSERT_TRUE(spin_lock.try_lock());
+  // Ensure it fails to lock when already held.
+  EXPECT_FALSE(spin_lock.try_lock());
+  spin_lock.unlock();
+}
+
+TEST(SpinLock, LockUnlockInC) {
+  pw::sync::SpinLock spin_lock;
+  pw_sync_SpinLock_CallLock(&spin_lock);
+  pw_sync_SpinLock_CallUnlock(&spin_lock);
+}
+
+TEST(SpinLock, TryLockUnlockInC) {
+  pw::sync::SpinLock spin_lock;
+  ASSERT_TRUE(pw_sync_SpinLock_CallTryLock(&spin_lock));
+  // Ensure it fails to lock when already held.
+  EXPECT_FALSE(pw_sync_SpinLock_CallTryLock(&spin_lock));
+  pw_sync_SpinLock_CallUnlock(&spin_lock);
+}
+
+}  // namespace
+}  // namespace pw::sync
diff --git a/pw_sync/spin_lock_facade_test_c.c b/pw_sync/spin_lock_facade_test_c.c
new file mode 100644
index 0000000..17d0fd04
--- /dev/null
+++ b/pw_sync/spin_lock_facade_test_c.c
@@ -0,0 +1,32 @@
+// 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_sync module spin_lock API from C. The return values
+// are checked in the main C++ tests.
+
+#include <stdbool.h>
+
+#include "pw_sync/spin_lock.h"
+
+void pw_sync_SpinLock_CallLock(pw_sync_SpinLock* spin_lock) {
+  pw_sync_SpinLock_Lock(spin_lock);
+}
+
+bool pw_sync_SpinLock_CallTryLock(pw_sync_SpinLock* spin_lock) {
+  return pw_sync_SpinLock_TryLock(spin_lock);
+}
+
+void pw_sync_SpinLock_CallUnlock(pw_sync_SpinLock* spin_lock) {
+  pw_sync_SpinLock_Unlock(spin_lock);
+}
diff --git a/pw_sync_stl/BUILD b/pw_sync_stl/BUILD
new file mode 100644
index 0000000..13b6d64
--- /dev/null
+++ b/pw_sync_stl/BUILD
@@ -0,0 +1,45 @@
+# 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 = "spin_lock_headers",
+    hdrs = [
+        "public/pw_sync_stl/spin_lock_inline.h",
+        "public/pw_sync_stl/spin_lock_native.h",
+        "public_overrides/pw_sync_backend/spin_lock_inline.h",
+        "public_overrides/pw_sync_backend/spin_lock_native.h",
+    ],
+    includes = [
+        "public",
+        "public_overrides",
+    ],
+)
+
+pw_cc_library(
+    name = "spin_lock",
+    deps = [
+        ":spin_lock_headers",
+        "//pw_sync:spin_lock_facade",
+        "//pw_sync:yield_core",
+    ],
+)
diff --git a/pw_sync_stl/BUILD.gn b/pw_sync_stl/BUILD.gn
new file mode 100644
index 0000000..eacd5dd
--- /dev/null
+++ b/pw_sync_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::sync::SpinLock.
+pw_source_set("spin_lock_backend") {
+  public_configs = [
+    ":public_include_path",
+    ":backend_config",
+  ]
+  public = [
+    "public/pw_sync_stl/spin_lock_inline.h",
+    "public/pw_sync_stl/spin_lock_native.h",
+    "public_overrides/pw_sync_backend/spin_lock_inline.h",
+    "public_overrides/pw_sync_backend/spin_lock_native.h",
+  ]
+  public_deps = [
+    "$dir_pw_sync:spin_lock.facade",
+    "$dir_pw_sync:yield_core",
+  ]
+}
+
+pw_doc_group("docs") {
+  sources = [ "docs.rst" ]
+}
diff --git a/pw_sync_stl/docs.rst b/pw_sync_stl/docs.rst
new file mode 100644
index 0000000..5d922d2
--- /dev/null
+++ b/pw_sync_stl/docs.rst
@@ -0,0 +1,8 @@
+.. _module-pw_sync_stl:
+
+-----------
+pw_sync_stl
+-----------
+This is a set of backends for pw_sync based on the C++ STL. It is not ready for
+use, and is under construction.
+
diff --git a/pw_sync_stl/public/pw_sync_stl/spin_lock_inline.h b/pw_sync_stl/public/pw_sync_stl/spin_lock_inline.h
new file mode 100644
index 0000000..57572d0
--- /dev/null
+++ b/pw_sync_stl/public/pw_sync_stl/spin_lock_inline.h
@@ -0,0 +1,41 @@
+// 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 "pw_sync/spin_lock.h"
+#include "pw_sync/yield_core.h"
+
+namespace pw::sync {
+
+inline SpinLock::SpinLock() : native_type_() {}
+
+inline void SpinLock::lock() {
+  while (!try_lock()) {
+    PW_SYNC_YIELD_CORE_FOR_SMT();
+  }
+}
+
+inline bool SpinLock::try_lock() {
+  return !native_type_.test_and_set(std::memory_order_acquire);
+}
+
+inline void SpinLock::unlock() {
+  native_type_.clear(std::memory_order_release);
+}
+
+inline SpinLock::native_handle_type SpinLock::native_handle() {
+  return native_type_;
+}
+
+}  // namespace pw::sync
diff --git a/pw_sync_stl/public/pw_sync_stl/spin_lock_native.h b/pw_sync_stl/public/pw_sync_stl/spin_lock_native.h
new file mode 100644
index 0000000..3358f8b
--- /dev/null
+++ b/pw_sync_stl/public/pw_sync_stl/spin_lock_native.h
@@ -0,0 +1,23 @@
+// 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 <atomic>
+
+namespace pw::sync::backend {
+
+using NativeSpinLock = std::atomic_flag;
+using NativeSpinLockHandle = std::atomic_flag&;
+
+}  // namespace pw::sync::backend
diff --git a/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_inline.h b/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_inline.h
new file mode 100644
index 0000000..0307f88
--- /dev/null
+++ b/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_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_sync_stl/spin_lock_inline.h"
diff --git a/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_native.h b/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_native.h
new file mode 100644
index 0000000..9d1922b
--- /dev/null
+++ b/pw_sync_stl/public_overrides/pw_sync_backend/spin_lock_native.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_sync_stl/spin_lock_native.h"
diff --git a/targets/host/target_toolchains.gni b/targets/host/target_toolchains.gni
index 51be296..73c61c0 100644
--- a/targets/host/target_toolchains.gni
+++ b/targets/host/target_toolchains.gni
@@ -29,6 +29,9 @@
   # Configure backend for logging facade.
   pw_log_BACKEND = "$dir_pw_log_basic"
 
+  # Configure backends for pw_sync's facades.
+  pw_sync_SPIN_LOCK_BACKEND = "$dir_pw_sync_stl:spin_lock_backend"
+
   # Configure backend for pw_sys_io facade.
   pw_sys_io_BACKEND = "$dir_pw_sys_io_stdio"