pw_sync_baremetal: Add simple mutex implementation

Adds a dummy mutex implementation for baremetal configurations.

The provided implementation makes a single attempt to acquire the
lock and asserts if it is unavailable. It does not perform interrupt
masking or disable global interrupts, so this implementation does
not support simultaneous multi-threaded environments including IRQs,
and is only meant to prevent data corruption.

Change-Id: Id122f890a37822c3b752b810e0e687f19f8c9dbd
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/45721
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Prashanth Swaminathan <prashanthsw@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
diff --git a/pw_sync_baremetal/BUILD b/pw_sync_baremetal/BUILD
index 69821e1..f3eeb51 100644
--- a/pw_sync_baremetal/BUILD
+++ b/pw_sync_baremetal/BUILD
@@ -46,3 +46,28 @@
         "//pw_sync:yield_core",
     ],
 )
+
+pw_cc_library(
+    name = "mutex_headers",
+    hdrs = [
+        "public/pw_sync_baremetal/mutex_inline.h",
+        "public/pw_sync_baremetal/mutex_native.h",
+        "public_overrides/pw_sync_backend/mutex_inline.h",
+        "public_overrides/pw_sync_backend/mutex_native.h",
+    ],
+    includes = [
+        "public",
+        "public_overrides",
+    ],
+    target_compatible_with = ["@platforms//os:none"],
+)
+
+pw_cc_library(
+    name = "mutex",
+    target_compatible_with = ["@platforms//os:none"],
+    deps = [
+        ":mutex_headers",
+        "//pw_assert",
+        "//pw_sync:mutex_facade",
+    ],
+)
diff --git a/pw_sync_baremetal/BUILD.gn b/pw_sync_baremetal/BUILD.gn
index 881e807..e862556 100644
--- a/pw_sync_baremetal/BUILD.gn
+++ b/pw_sync_baremetal/BUILD.gn
@@ -33,7 +33,8 @@
 # asserts if it is unavailable. It does not perform interrupt masking or disable
 # global interrupts, so this implementation does not support simultaneous
 # multi-threaded environments including IRQs, and is only meant to prevent
-# data corruption.
+# data corruption. This implementation is not yet set up to support hardware
+# multi-threading (SMP, SMT, etc).
 pw_source_set("interrupt_spin_lock") {
   public_configs = [
     ":public_include_path",
@@ -52,6 +53,27 @@
   ]
 }
 
+# This target provides the backend for pw::sync::Mutex.
+# The provided implementation makes a single attempt to acquire the lock and
+# asserts if it is unavailable. This implementation is not yet set up to support
+# hardware multi-threading (SMP, SMT, etc).
+pw_source_set("mutex") {
+  public_configs = [
+    ":public_include_path",
+    ":backend_config",
+  ]
+  public = [
+    "public/pw_sync_baremetal/mutex_inline.h",
+    "public/pw_sync_baremetal/mutex_native.h",
+    "public_overrides/pw_sync_backend/mutex_inline.h",
+    "public_overrides/pw_sync_backend/mutex_native.h",
+  ]
+  public_deps = [
+    "$dir_pw_assert",
+    "$dir_pw_sync:mutex.facade",
+  ]
+}
+
 pw_doc_group("docs") {
   sources = [ "docs.rst" ]
 }
diff --git a/pw_sync_baremetal/docs.rst b/pw_sync_baremetal/docs.rst
index 1fbd99e..5984332 100644
--- a/pw_sync_baremetal/docs.rst
+++ b/pw_sync_baremetal/docs.rst
@@ -4,8 +4,25 @@
 pw_sync_baremetal
 -----------------
 This is a set of backends for pw_sync that works on baremetal targets. It is not
-ready for use, and is under construction. The provided implementation makes a
-single attempt to acquire the lock and asserts if it is unavailable. It does not
-perform interrupt masking or disable global interrupts, so this implementation
-does not support simultaneous multi-threaded environments including IRQs, and is
-only meant to prevent data corruption.
+ready for use, and is under construction.
+
+.. note::
+  All constructs in this baremetal backend do not support hardware multi-threading
+  (SMP, SMT, etc).
+
+.. warning::
+  It does not perform interrupt masking or disable global interrupts. This is not
+  safe to use yet!
+
+-------------------------------------
+pw_sync_baremetal's InterruptSpinLock
+-------------------------------------
+The interrupt spin-lock implementation makes a single attempt to acquire the lock
+and asserts if it is unavailable. It does not perform interrupt masking or disable global
+interrupts.
+
+-------------------------
+pw_sync_baremetal's Mutex
+-------------------------
+The mutex implementation makes a single attempt to acquire the lock and asserts if
+it is unavailable.
diff --git a/pw_sync_baremetal/public/pw_sync_baremetal/mutex_inline.h b/pw_sync_baremetal/public/pw_sync_baremetal/mutex_inline.h
new file mode 100644
index 0000000..70a10c2
--- /dev/null
+++ b/pw_sync_baremetal/public/pw_sync_baremetal/mutex_inline.h
@@ -0,0 +1,38 @@
+// Copyright 2021 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_assert/assert.h"
+#include "pw_sync/mutex.h"
+
+namespace pw::sync {
+
+inline Mutex::Mutex() : native_type_() {}
+
+inline Mutex::~Mutex() {}
+
+inline void Mutex::lock() { PW_ASSERT(try_lock()); }
+
+inline bool Mutex::try_lock() {
+  return !native_type_.test_and_set(std::memory_order_acquire);
+}
+
+inline void Mutex::unlock() {
+  PW_ASSERT(native_type_.test_and_set(std::memory_order_acquire));
+  native_type_.clear(std::memory_order_release);
+}
+
+inline Mutex::native_handle_type Mutex::native_handle() { return native_type_; }
+
+}  // namespace pw::sync
diff --git a/pw_sync_baremetal/public/pw_sync_baremetal/mutex_native.h b/pw_sync_baremetal/public/pw_sync_baremetal/mutex_native.h
new file mode 100644
index 0000000..f5d6e13
--- /dev/null
+++ b/pw_sync_baremetal/public/pw_sync_baremetal/mutex_native.h
@@ -0,0 +1,23 @@
+// Copyright 2021 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 NativeMutex = std::atomic_flag;
+using NativeMutexHandle = std::atomic_flag&;
+
+}  // namespace pw::sync::backend
diff --git a/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_inline.h b/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_inline.h
new file mode 100644
index 0000000..f55dcc2
--- /dev/null
+++ b/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_inline.h
@@ -0,0 +1,16 @@
+// Copyright 2021 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_baremetal/mutex_inline.h"
diff --git a/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_native.h b/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_native.h
new file mode 100644
index 0000000..9d6b9e0
--- /dev/null
+++ b/pw_sync_baremetal/public_overrides/pw_sync_backend/mutex_native.h
@@ -0,0 +1,16 @@
+// Copyright 2021 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_baremetal/mutex_native.h"
diff --git a/targets/arduino/target_toolchains.gni b/targets/arduino/target_toolchains.gni
index cba6db8..e0b5907 100644
--- a/targets/arduino/target_toolchains.gni
+++ b/targets/arduino/target_toolchains.gni
@@ -46,6 +46,7 @@
   pw_log_BACKEND = dir_pw_log_basic
   pw_sync_INTERRUPT_SPIN_LOCK_BACKEND =
       "$dir_pw_sync_baremetal:interrupt_spin_lock"
+  pw_sync_MUTEX_BACKEND = "$dir_pw_sync_baremetal:mutex"
   pw_sys_io_BACKEND = dir_pw_sys_io_arduino
   pw_rpc_system_server_BACKEND =
       "$dir_pigweed/targets/arduino:system_rpc_server"
diff --git a/targets/lm3s6965evb_qemu/target_toolchains.gni b/targets/lm3s6965evb_qemu/target_toolchains.gni
index b0138af..c52deb2 100644
--- a/targets/lm3s6965evb_qemu/target_toolchains.gni
+++ b/targets/lm3s6965evb_qemu/target_toolchains.gni
@@ -42,6 +42,7 @@
   pw_sys_io_BACKEND = dir_pw_sys_io_baremetal_lm3s6965evb
   pw_sync_INTERRUPT_SPIN_LOCK_BACKEND =
       "$dir_pw_sync_baremetal:interrupt_spin_lock"
+  pw_sync_MUTEX_BACKEND = "$dir_pw_sync_baremetal:mutex"
 
   # pw_cpu_exception_armv7m tests do not work as expected in QEMU. It does not
   # appear the divide-by-zero traps as expected when enabled, which prevents the
diff --git a/targets/stm32f429i_disc1/target_toolchains.gni b/targets/stm32f429i_disc1/target_toolchains.gni
index d20dba0..353476f 100644
--- a/targets/stm32f429i_disc1/target_toolchains.gni
+++ b/targets/stm32f429i_disc1/target_toolchains.gni
@@ -52,6 +52,7 @@
       "$dir_pw_cpu_exception_cortex_m:support_armv7m"
   pw_sync_INTERRUPT_SPIN_LOCK_BACKEND =
       "$dir_pw_sync_baremetal:interrupt_spin_lock"
+  pw_sync_MUTEX_BACKEND = "$dir_pw_sync_baremetal:mutex"
   pw_log_BACKEND = dir_pw_log_basic
   pw_sys_io_BACKEND = dir_pw_sys_io_baremetal_stm32f429
   pw_rpc_system_server_BACKEND =