embos: add third_party, SystemClock, and SpinLock support
Adds initial support for embOS v4 for 32bit targets. For now this
only adds third_party support to depend on embOS's RTOS.h header,
the pw::chrono::SystemClock based on OS_GetTime32 and the
pw::sync::SpinLock based on OS_IncDI & OS_DecRI.
Change-Id: I6faf815ab05a0b00b7006b4bcc62df713b219dfe
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/35601
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Ewout van Bekkum <ewout@google.com>
diff --git a/modules.gni b/modules.gni
index 188e7b1..caf19fe 100644
--- a/modules.gni
+++ b/modules.gni
@@ -30,6 +30,7 @@
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_embos = get_path_info("pw_chrono_embos", "abspath")
dir_pw_chrono_freertos = get_path_info("pw_chrono_freertos", "abspath")
dir_pw_chrono_stl = get_path_info("pw_chrono_stl", "abspath")
dir_pw_chrono_threadx = get_path_info("pw_chrono_threadx", "abspath")
@@ -76,6 +77,7 @@
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_embos = get_path_info("pw_sync_embos", "abspath")
dir_pw_sync_freertos = get_path_info("pw_sync_freertos", "abspath")
dir_pw_sync_baremetal = get_path_info("pw_sync_baremetal", "abspath")
dir_pw_sync_stl = get_path_info("pw_sync_stl", "abspath")
diff --git a/pw_chrono_embos/BUILD b/pw_chrono_embos/BUILD
new file mode 100644
index 0000000..a65d083
--- /dev/null
+++ b/pw_chrono_embos/BUILD
@@ -0,0 +1,52 @@
+# 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.
+
+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_embos/config.h",
+ "public/pw_chrono_embos/system_clock_config.h",
+ "public/pw_chrono_embos/system_clock_constants.h",
+ "public_overrides/pw_chrono_backend/system_clock_config.h",
+ ],
+ includes = [
+ "public",
+ "public_overrides",
+ ],
+ deps = [
+ "//pw_chrono:epoch",
+ ],
+)
+
+pw_cc_library(
+ name = "system_clock",
+ srcs = [
+ "system_clock.cc",
+ ],
+ deps = [
+ ":system_clock_headers",
+ "//pw_chrono:system_clock_facade",
+ # TODO(pwbug/317): This should depend on embOS but our third parties
+ # currently do not have Bazel support.
+ ],
+)
diff --git a/pw_chrono_embos/BUILD.gn b/pw_chrono_embos/BUILD.gn
new file mode 100644
index 0000000..0d9e63a
--- /dev/null
+++ b/pw_chrono_embos/BUILD.gn
@@ -0,0 +1,73 @@
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/module_config.gni")
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_docgen/docs.gni")
+
+declare_args() {
+ # The build target that overrides the default configuration options for this
+ # module. This should point to a source set that provides defines through a
+ # public config (which may -include a file or add defines directly).
+ pw_chrono_embos_CONFIG = pw_build_DEFAULT_MODULE_CONFIG
+}
+
+config("public_include_path") {
+ include_dirs = [ "public" ]
+ visibility = [ ":*" ]
+}
+
+config("backend_config") {
+ include_dirs = [ "public_overrides" ]
+ visibility = [ ":*" ]
+}
+
+pw_source_set("config") {
+ public = [ "public/pw_chrono_embos/config.h" ]
+ public_configs = [ ":public_include_path" ]
+ public_deps = [
+ "$dir_pw_third_party/embos",
+ pw_chrono_embos_CONFIG,
+ ]
+}
+
+# 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_embos/system_clock_config.h",
+ "public/pw_chrono_embos/system_clock_constants.h",
+ "public_overrides/pw_chrono_backend/system_clock_config.h",
+ ]
+ public_deps = [
+ ":config",
+ "$dir_pw_chrono:epoch",
+ "$dir_pw_chrono:system_clock.facade",
+ "$dir_pw_third_party/embos",
+ ]
+ sources = [ "system_clock.cc" ]
+ deps = [
+ "$dir_pw_chrono:system_clock.facade",
+ "$dir_pw_sync:spin_lock",
+ ]
+}
+
+pw_doc_group("docs") {
+ sources = [ "docs.rst" ]
+}
diff --git a/pw_chrono_embos/docs.rst b/pw_chrono_embos/docs.rst
new file mode 100644
index 0000000..aedc5b4
--- /dev/null
+++ b/pw_chrono_embos/docs.rst
@@ -0,0 +1,32 @@
+.. _module-pw_chrono_embos:
+
+---------------
+pw_chrono_embos
+---------------
+``pw_chrono_embos`` is a collection of ``pw_chrono`` backends that are
+implemented using embOS v4 for 32bit targets.
+
+.. warning::
+ This module is under construction, not ready for use, and the documentation
+ is incomplete.
+
+SystemClock backend
+-------------------
+The embOS based ``system_clock`` backend implements the
+``pw_chrono:system_clock`` facade by using ``OS_GetTime32()``. Before the global
+singleton SystemClock's SpinLock is constructed the raw result is returned,
+after the overflows are managed in a thread and IRQ safe manner to produce a
+signed 64 bit timestamp. Note that this does NOT use ``OS_GetTime_us64()`` which
+is not always available, this could be considered for a future alternative
+backend for the SystemClock.
+
+The ``SystemClock::now()`` must be used more than once per overflow of the
+native embOS ``OS_GetTime32()`` overflow. Note that this duration may
+vary if ``OS_SUPPORT_TICKLESS`` is used.
+
+Build targets
+-------------
+The GN build for ``pw_chrono_embos`` has one target: ``system_clock``.
+The ``system_clock`` target provides the
+``pw_chrono_backend/system_clock_config.h`` and ``pw_chrono_embos/config.h``
+headers and the backend for the ``pw_chrono:system_clock``.
diff --git a/pw_chrono_embos/public/pw_chrono_embos/config.h b/pw_chrono_embos/public/pw_chrono_embos/config.h
new file mode 100644
index 0000000..ef248b5
--- /dev/null
+++ b/pw_chrono_embos/public/pw_chrono_embos/config.h
@@ -0,0 +1,42 @@
+// 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.
+// Configuration macros for the tokenizer module.
+#pragma once
+
+#include <assert.h>
+
+// For the embOS backend of the SystemClock, there is no way to determine the
+// system timer's tick interval/frequency. By default most ports happen to be at
+// 1ms intervals (i.e. 1kHz), however this can be tuned for different
+// applications.
+// The resulting clock period is defined in seconds = 1 / denominator.
+// For example the default is configured to 1/1000 seconds per clock tick.
+#ifndef PW_CHRONO_EMBOS_CFG_CLOCK_PERIOD_SECONDS_DENOMINATOR
+#define PW_CHRONO_EMBOS_CFG_CLOCK_PERIOD_SECONDS_DENOMINATOR 1000
+#endif // PW_CHRONO_EMBOS_CFG_CLOCK_PERIOD_SECONDS_DENOMINATOR
+
+static_assert(PW_CHRONO_EMBOS_CFG_CLOCK_PERIOD_SECONDS_DENOMINATOR >= 1,
+ "the denominator must be positive and cannot be fractional");
+
+// Because the SystemClock::now() implementation requires the user to invoke it
+// more than once per overflow period, the max timeout is set to ensure that
+// blocking indefinitely on a single primitive will meet this constraint with
+// margin (i.e. more than twice per overflow).
+#ifndef PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT
+#define PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT (0x7FFFFFFF / 3)
+#endif // PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT
+
+static_assert((PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT > 0) &&
+ (PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT <= 0x7FFFFFFF),
+ "Invalid MAX timeout configuration");
diff --git a/pw_chrono_embos/public/pw_chrono_embos/system_clock_config.h b/pw_chrono_embos/public/pw_chrono_embos/system_clock_config.h
new file mode 100644
index 0000000..7b2d21a
--- /dev/null
+++ b/pw_chrono_embos/public/pw_chrono_embos/system_clock_config.h
@@ -0,0 +1,43 @@
+// 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_chrono_embos/config.h"
+
+// embOS does not have an API to determine the tick rate/period at compile time,
+// instead require the user to specify this through the configuration. Note it
+// is configured by the user as Hz, ergo the numerator is always 1.
+#define PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_NUMERATOR 1
+#define PW_CHRONO_SYSTEM_CLOCK_PERIOD_SECONDS_DENOMINATOR \
+ PW_CHRONO_EMBOS_CFG_CLOCK_PERIOD_SECONDS_DENOMINATOR
+
+#ifdef __cplusplus
+
+#include "pw_chrono/epoch.h"
+
+namespace pw::chrono::backend {
+
+// The embOS clock starts at zero during initialization, approximately the
+// time since boot.
+inline constexpr Epoch kSystemClockEpoch = pw::chrono::Epoch::kTimeSinceBoot;
+
+// The current backend implementation is not NMI safe.
+inline constexpr bool kSystemClockNmiSafe = false;
+
+// The embOS clock halts when the systick interrupt is masked.
+inline constexpr bool kSystemClockFreeRunning = false;
+
+} // namespace pw::chrono::backend
+
+#endif // __cplusplus
diff --git a/pw_chrono_embos/public/pw_chrono_embos/system_clock_constants.h b/pw_chrono_embos/public/pw_chrono_embos/system_clock_constants.h
new file mode 100644
index 0000000..1ec6e8f
--- /dev/null
+++ b/pw_chrono_embos/public/pw_chrono_embos/system_clock_constants.h
@@ -0,0 +1,26 @@
+// 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_chrono/system_clock.h"
+#include "pw_chrono_embos/config.h"
+
+namespace pw::chrono::embos {
+
+// Max timeout to be used by users of the embOS's pw::chrono::SystemClock
+// backend provided by this module.
+inline constexpr SystemClock::duration kMaxTimeout =
+ SystemClock::duration(PW_CHRONO_EMBOS_CFG_MAX_TIMEOUT);
+
+} // namespace pw::chrono::embos
diff --git a/pw_chrono_embos/public_overrides/pw_chrono_backend/system_clock_config.h b/pw_chrono_embos/public_overrides/pw_chrono_backend/system_clock_config.h
new file mode 100644
index 0000000..45e2179
--- /dev/null
+++ b/pw_chrono_embos/public_overrides/pw_chrono_backend/system_clock_config.h
@@ -0,0 +1,19 @@
+// 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.
+
+// 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_embos/system_clock_config.h"
diff --git a/pw_chrono_embos/system_clock.cc b/pw_chrono_embos/system_clock.cc
new file mode 100644
index 0000000..8de700e
--- /dev/null
+++ b/pw_chrono_embos/system_clock.cc
@@ -0,0 +1,86 @@
+// 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.
+
+#include "pw_chrono/system_clock.h"
+
+#include <atomic>
+#include <chrono>
+#include <limits>
+#include <mutex>
+
+#include "RTOS.h"
+#include "pw_sync/spin_lock.h"
+
+namespace pw::chrono::backend {
+namespace {
+
+// Extension wrapping pw::SpinLock to allow an atomic to be used to determine
+// whether it has been constructed and is ready to be used.
+class ConstructionSignalingSpinLock : public sync::SpinLock {
+ public:
+ ConstructionSignalingSpinLock(std::atomic<bool>& constructed_signal)
+ : sync::SpinLock() {
+ // Note that the memory order is relaxed because C++ global static
+ // construction is a single threaded environment.
+ constructed_signal.store(true, std::memory_order_relaxed);
+ };
+};
+
+// This is POD, meaning this atomic is available before static C++ global
+// constructors are run.
+std::atomic<bool> system_clock_spin_lock_constructed = {false};
+
+ConstructionSignalingSpinLock system_clock_spin_lock(
+ system_clock_spin_lock_constructed);
+
+int64_t overflow_tick_count = 0;
+uint32_t native_tick_count = 0;
+static_assert(!SystemClock::is_nmi_safe,
+ "global state is not atomic nor double buferred");
+
+static_assert(sizeof(void*) == 4, "this backend only supports 32 bit targets!");
+
+inline uint32_t GetUint32TickCount() {
+ // embOS returns a signed 32 bit value, however according to their developers
+ // the binary value continues to increment like an unsigned value, ergo we
+ // instead reinterpret the tick count as the raw underlying 32 bit unsigned
+ // tick count.
+ return static_cast<uint32_t>(OS_GetTime32());
+}
+
+// The tick count resets to 0, ergo the overflow count is the max count + 1.
+constexpr int64_t kNativeOverflowTickCount =
+ static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 1;
+
+} // namespace
+
+int64_t GetSystemClockTickCount() {
+ // Note that the memory order is relaxed because C++ global static
+ // construction is a single threaded environment.
+ if (!system_clock_spin_lock_constructed.load(std::memory_order_relaxed)) {
+ return GetUint32TickCount();
+ }
+
+ std::lock_guard lock(system_clock_spin_lock);
+ const uint32_t new_native_tick_count = GetUint32TickCount();
+ // WARNING: This must be called more than once per overflow period!
+ if (new_native_tick_count < native_tick_count) {
+ // Native tick count overflow detected!
+ overflow_tick_count += kNativeOverflowTickCount;
+ }
+ native_tick_count = new_native_tick_count;
+ return overflow_tick_count + native_tick_count;
+}
+
+} // namespace pw::chrono::backend
diff --git a/pw_sync_embos/BUILD b/pw_sync_embos/BUILD
new file mode 100644
index 0000000..88e824e
--- /dev/null
+++ b/pw_sync_embos/BUILD
@@ -0,0 +1,50 @@
+# 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.
+
+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_embos/spin_lock_inline.h",
+ "public/pw_sync_embos/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",
+ ],
+ # TODO(pwbug/317): This should depend on embOS but our third parties
+ # currently do not have Bazel support.
+)
+
+pw_cc_library(
+ name = "spin_lock",
+ srcs = [
+ "spin_lock.cc",
+ ],
+ deps = [
+ ":spin_lock_headers",
+ "//pw_sync:spin_lock_facade",
+ ],
+)
+
diff --git a/pw_sync_embos/BUILD.gn b/pw_sync_embos/BUILD.gn
new file mode 100644
index 0000000..cbb3d02
--- /dev/null
+++ b/pw_sync_embos/BUILD.gn
@@ -0,0 +1,54 @@
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_chrono/backend.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") {
+ public_configs = [
+ ":public_include_path",
+ ":backend_config",
+ ]
+ public = [
+ "public/pw_sync_embos/spin_lock_inline.h",
+ "public/pw_sync_embos/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_third_party/embos" ]
+ sources = [ "spin_lock.cc" ]
+ deps = [
+ "$dir_pw_assert",
+ "$dir_pw_sync:spin_lock.facade",
+ "$dir_pw_third_party/embos",
+ ]
+}
+
+pw_doc_group("docs") {
+ sources = [ "docs.rst" ]
+}
diff --git a/pw_sync_embos/docs.rst b/pw_sync_embos/docs.rst
new file mode 100644
index 0000000..19e1636
--- /dev/null
+++ b/pw_sync_embos/docs.rst
@@ -0,0 +1,8 @@
+.. _module-pw_sync_embos:
+
+-------------
+pw_sync_embos
+-------------
+This is a set of backends for pw_sync based on embOS v4. It is not ready for
+use, and is under construction.
+
diff --git a/pw_sync_embos/public/pw_sync_embos/spin_lock_inline.h b/pw_sync_embos/public/pw_sync_embos/spin_lock_inline.h
new file mode 100644
index 0000000..7fb6f62
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/spin_lock_inline.h
@@ -0,0 +1,29 @@
+// 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/spin_lock.h"
+
+namespace pw::sync {
+
+// TODO(ewout): update the SpinLock facade to be constexpr constructable which
+// should help use of spin locks before C++ construction massively and appears
+// to be portable.
+inline SpinLock::SpinLock() : native_type_{.locked{false}} {}
+
+inline SpinLock::native_handle_type SpinLock::native_handle() {
+ return native_type_;
+}
+
+} // namespace pw::sync
diff --git a/pw_sync_embos/public/pw_sync_embos/spin_lock_native.h b/pw_sync_embos/public/pw_sync_embos/spin_lock_native.h
new file mode 100644
index 0000000..42e7e42
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/spin_lock_native.h
@@ -0,0 +1,27 @@
+// 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>
+
+#include "RTOS.h"
+
+namespace pw::sync::backend {
+
+struct NativeSpinLock {
+ std::atomic<bool> locked; // Used to detect recursion.
+};
+using NativeSpinLockHandle = NativeSpinLock&;
+
+} // namespace pw::sync::backend
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_inline.h b/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_inline.h
new file mode 100644
index 0000000..434f3bc
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_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_embos/spin_lock_inline.h"
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_native.h b/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_native.h
new file mode 100644
index 0000000..6d8075a
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/spin_lock_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_embos/spin_lock_native.h"
diff --git a/pw_sync_embos/spin_lock.cc b/pw_sync_embos/spin_lock.cc
new file mode 100644
index 0000000..2a5405a
--- /dev/null
+++ b/pw_sync_embos/spin_lock.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "pw_sync/spin_lock.h"
+
+#include "RTOS.h"
+#include "pw_assert/assert.h"
+
+namespace pw::sync {
+
+void SpinLock::lock() {
+ OS_IncDI();
+ // We can't deadlock here so crash instead.
+ PW_CHECK(!native_type_.locked.load(std::memory_order_relaxed),
+ "Recursive SpinLock::lock() detected");
+ native_type_.locked.store(true, std::memory_order_relaxed);
+}
+
+bool SpinLock::try_lock() {
+ OS_IncDI();
+ if (native_type_.locked.load(std::memory_order_relaxed)) {
+ OS_DecRI(); // Already locked, restore interrupts and bail out.
+ return false;
+ }
+ native_type_.locked.store(true, std::memory_order_relaxed);
+ return true;
+}
+
+void SpinLock::unlock() {
+ native_type_.locked.store(false, std::memory_order_relaxed);
+ OS_DecRI();
+}
+
+} // namespace pw::sync
diff --git a/third_party/embos/BUILD.gn b/third_party/embos/BUILD.gn
new file mode 100644
index 0000000..ee98b32
--- /dev/null
+++ b/third_party/embos/BUILD.gn
@@ -0,0 +1,39 @@
+# 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("embos.gni")
+
+# This file defines a GN source_set for an external installation of embOS.
+# To use, checkout the embOS source into a directory, then set the build arg
+# dir_pw_third_party_embOS to point to that directory. The embOS library
+# will be available in GN at "$dir_pw_third_party/embos".
+if (dir_pw_third_party_embos_include != "") {
+ config("public_includes") {
+ include_dirs = [ "$dir_pw_third_party_embos_include" ]
+ visibility = [ ":*" ]
+ }
+
+ pw_source_set("embos") {
+ public_configs = [ ":public_includes" ]
+ allow_circular_includes_from = [ pw_third_party_embos_PORT ]
+ public_deps = [ pw_third_party_embos_PORT ]
+ public = [ "$dir_pw_third_party_embos_include/RTOS.h" ]
+ }
+} else {
+ group("embos") {
+ }
+}
diff --git a/third_party/embos/embos.gni b/third_party/embos/embos.gni
new file mode 100644
index 0000000..b2d3e25
--- /dev/null
+++ b/third_party/embos/embos.gni
@@ -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.
+
+declare_args() {
+ # If compiling backends with embOS, this variable is set to the path to the
+ # embOS include directory. When set, a pw_source_set for the embos library
+ # is created at "$dir_pw_third_party/embos".
+ dir_pw_third_party_embos_include = ""
+
+ # The pw_source_set which provides the port specific includes and sources.
+ pw_third_party_embos_PORT = ""
+}