pw_sync_embos: add Semaphore support
Adds BinarySemaphore and CountingSemaphore support for embOS v4.
Change-Id: Iae3bbc9f6e9fe977e7906a44e1b14ecdfa5f5e0a
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/35883
Commit-Queue: Ewout van Bekkum <ewout@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
diff --git a/pw_sync_embos/BUILD b/pw_sync_embos/BUILD
index 56777c9..98e4739 100644
--- a/pw_sync_embos/BUILD
+++ b/pw_sync_embos/BUILD
@@ -22,6 +22,71 @@
licenses(["notice"]) # Apache License 2.0
pw_cc_library(
+ name = "binary_semaphore_headers",
+ hdrs = [
+ "public/pw_sync_embos/binary_semaphore_inline.h",
+ "public/pw_sync_embos/binary_semaphore_native.h",
+ "public_overrides/pw_sync_backend/binary_semaphore_inline.h",
+ "public_overrides/pw_sync_backend/binary_semaphore_native.h",
+ ],
+ includes = [
+ "public",
+ "public_overrides",
+ ],
+ deps = [
+ # TODO(pwbug/317): This should depend on embOS but our third parties
+ # currently do not have Bazel support.
+ "//pw_chrono:system_clock",
+ "//pw_chrono_embos:system_clock_headers",
+ ],
+)
+
+pw_cc_library(
+ name = "binary_semaphore",
+ srcs = [
+ "binary_semaphore.cc",
+ ],
+ deps = [
+ ":binary_semaphore_headers",
+ "//pw_interrupt:context",
+ "//pw_sync:binary_semaphore_facade",
+ ],
+)
+
+pw_cc_library(
+ name = "counting_semaphore_headers",
+ hdrs = [
+ "public/pw_sync_embos/counting_semaphore_inline.h",
+ "public/pw_sync_embos/counting_semaphore_native.h",
+ "public_overrides/pw_sync_backend/counting_semaphore_inline.h",
+ "public_overrides/pw_sync_backend/counting_semaphore_native.h",
+ ],
+ includes = [
+ "public",
+ "public_overrides",
+ ],
+ deps = [
+ # TODO(pwbug/317): This should depend on embOS but our third parties
+ # currently do not have Bazel support.
+ "//pw_chrono:system_clock",
+ "//pw_chrono_embos:system_clock_headers",
+ ],
+)
+
+pw_cc_library(
+ name = "counting_semaphore",
+ srcs = [
+ "counting_semaphore.cc",
+ ],
+ deps = [
+ ":counting_semaphore_headers",
+ "//pw_interrupt:context",
+ "//pw_sync:counting_semaphore_facade",
+ ],
+)
+
+
+pw_cc_library(
name = "mutex_headers",
hdrs = [
"public/pw_sync_embos/mutex_inline.h",
diff --git a/pw_sync_embos/BUILD.gn b/pw_sync_embos/BUILD.gn
index 4fa9b3d..abc95d7 100644
--- a/pw_sync_embos/BUILD.gn
+++ b/pw_sync_embos/BUILD.gn
@@ -28,6 +28,62 @@
visibility = [ ":*" ]
}
+# This target provides the backend for pw::sync::BinarySemaphore.
+pw_source_set("binary_semaphore") {
+ public_configs = [
+ ":public_include_path",
+ ":backend_config",
+ ]
+ public = [
+ "public/pw_sync_embos/binary_semaphore_inline.h",
+ "public/pw_sync_embos/binary_semaphore_native.h",
+ "public_overrides/pw_sync_backend/binary_semaphore_inline.h",
+ "public_overrides/pw_sync_backend/binary_semaphore_native.h",
+ ]
+ public_deps = [
+ "$dir_pw_assert",
+ "$dir_pw_chrono:system_clock",
+ "$dir_pw_chrono_embos:system_clock",
+ "$dir_pw_interrupt:context",
+ "$dir_pw_third_party/embos",
+ ]
+ sources = [ "binary_semaphore.cc" ]
+ deps = [ "$dir_pw_sync:binary_semaphore.facade" ]
+ assert(
+ pw_chrono_SYSTEM_CLOCK_BACKEND == "" ||
+ pw_chrono_SYSTEM_CLOCK_BACKEND == "$dir_pw_chrono_embos:system_clock",
+ "The embOS pw::sync::BinarySemaphore backend only works with the " +
+ "embOS pw::chrono::SystemClock backend.")
+}
+
+# This target provides the backend for pw::sync::CountingSemaphore.
+pw_source_set("counting_semaphore") {
+ public_configs = [
+ ":public_include_path",
+ ":backend_config",
+ ]
+ public = [
+ "public/pw_sync_embos/counting_semaphore_inline.h",
+ "public/pw_sync_embos/counting_semaphore_native.h",
+ "public_overrides/pw_sync_backend/counting_semaphore_inline.h",
+ "public_overrides/pw_sync_backend/counting_semaphore_native.h",
+ ]
+ public_deps = [
+ "$dir_pw_assert",
+ "$dir_pw_chrono:system_clock",
+ "$dir_pw_chrono_embos:system_clock",
+ "$dir_pw_interrupt:context",
+ "$dir_pw_third_party/embos",
+ ]
+ sources = [ "counting_semaphore.cc" ]
+ deps = [ "$dir_pw_sync:counting_semaphore.facade" ]
+ assert(
+ pw_chrono_SYSTEM_CLOCK_BACKEND == "" ||
+ pw_chrono_SYSTEM_CLOCK_BACKEND == "$dir_pw_chrono_embos:system_clock",
+ "The embOS pw::sync::CountingSemaphore backend only works with " +
+ "the embOS pw::chrono::SystemClock backend.")
+}
+
# This target provides the backend for pw::sync::Mutex.
pw_source_set("mutex") {
public_configs = [
diff --git a/pw_sync_embos/binary_semaphore.cc b/pw_sync_embos/binary_semaphore.cc
new file mode 100644
index 0000000..379dbd4
--- /dev/null
+++ b/pw_sync_embos/binary_semaphore.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/binary_semaphore.h"
+
+#include <algorithm>
+
+#include "RTOS.h"
+#include "pw_assert/assert.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_chrono_embos/system_clock_constants.h"
+#include "pw_interrupt/context.h"
+
+using pw::chrono::SystemClock;
+using pw::chrono::embos::kMaxTimeout;
+
+namespace pw::sync {
+
+bool BinarySemaphore::try_acquire_for(SystemClock::duration for_at_least) {
+ PW_DCHECK(!interrupt::InInterruptContext());
+
+ // Clamp negative durations to be 0 which maps to non-blocking.
+ for_at_least = std::max(for_at_least, SystemClock::duration::zero());
+
+ while (for_at_least > kMaxTimeout) {
+ if (OS_WaitCSemaTimed(&native_type_, kMaxTimeout.count())) {
+ return true;
+ }
+ for_at_least -= kMaxTimeout;
+ }
+ return OS_WaitCSemaTimed(&native_type_, for_at_least.count());
+}
+
+} // namespace pw::sync
diff --git a/pw_sync_embos/counting_semaphore.cc b/pw_sync_embos/counting_semaphore.cc
new file mode 100644
index 0000000..e46a36b
--- /dev/null
+++ b/pw_sync_embos/counting_semaphore.cc
@@ -0,0 +1,59 @@
+// 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/counting_semaphore.h"
+
+#include <algorithm>
+
+#include "RTOS.h"
+#include "pw_assert/assert.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_chrono_embos/system_clock_constants.h"
+#include "pw_interrupt/context.h"
+
+using pw::chrono::SystemClock;
+using pw::chrono::embos::kMaxTimeout;
+
+namespace pw::sync {
+
+void CountingSemaphore::release(ptrdiff_t update) {
+ for (; update > 0; --update) {
+ // There is no API to atomically detect overflow, however debug builds of
+ // embOS call OS_Error() internally when overflow is detected for the native
+ // token representation. Rather than enter a critical section both due to
+ // cost and potential direct use of the native handle, a lazy check is used
+ // for debug builds which may not trigger on the initial overflow.
+ PW_DCHECK_UINT_LE(OS_GetCSemaValue(&native_type_),
+ CountingSemaphore::max(),
+ "Overflowed counting semaphore.");
+ OS_SignalCSema(&native_type_);
+ }
+}
+
+bool CountingSemaphore::try_acquire_for(SystemClock::duration for_at_least) {
+ PW_DCHECK(!interrupt::InInterruptContext());
+
+ // Clamp negative durations to be 0 which maps to non-blocking.
+ for_at_least = std::max(for_at_least, SystemClock::duration::zero());
+
+ while (for_at_least > kMaxTimeout) {
+ if (OS_WaitCSemaTimed(&native_type_, kMaxTimeout.count())) {
+ return true;
+ }
+ for_at_least -= kMaxTimeout;
+ }
+ return OS_WaitCSemaTimed(&native_type_, for_at_least.count());
+}
+
+} // namespace pw::sync
diff --git a/pw_sync_embos/public/pw_sync_embos/binary_semaphore_inline.h b/pw_sync_embos/public/pw_sync_embos/binary_semaphore_inline.h
new file mode 100644
index 0000000..3996851
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/binary_semaphore_inline.h
@@ -0,0 +1,51 @@
+// 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 "RTOS.h"
+#include "pw_assert/light.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_chrono_embos/system_clock_constants.h"
+#include "pw_interrupt/context.h"
+#include "pw_sync/binary_semaphore.h"
+
+namespace pw::sync {
+
+inline BinarySemaphore::BinarySemaphore() : native_type_() {
+ OS_CreateCSema(&native_type_, 0);
+}
+
+inline BinarySemaphore::~BinarySemaphore() { OS_DeleteCSema(&native_type_); }
+
+inline void BinarySemaphore::release() { OS_SignalCSemaMax(&native_type_, 1); }
+
+inline void BinarySemaphore::acquire() {
+ PW_ASSERT(!interrupt::InInterruptContext());
+ OS_WaitCSema(&native_type_);
+}
+
+inline bool BinarySemaphore::try_acquire() noexcept {
+ return OS_CSemaRequest(&native_type_) != 0;
+}
+
+inline bool BinarySemaphore::try_acquire_until(
+ chrono::SystemClock::time_point until_at_least) {
+ return try_acquire_for(until_at_least - chrono::SystemClock::now());
+}
+
+inline BinarySemaphore::native_handle_type BinarySemaphore::native_handle() {
+ return native_type_;
+}
+
+} // namespace pw::sync
diff --git a/pw_sync_embos/public/pw_sync_embos/binary_semaphore_native.h b/pw_sync_embos/public/pw_sync_embos/binary_semaphore_native.h
new file mode 100644
index 0000000..c92afa9
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/binary_semaphore_native.h
@@ -0,0 +1,30 @@
+// 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 <limits>
+
+#include "RTOS.h"
+
+namespace pw::sync::backend {
+
+using NativeBinarySemaphore = OS_CSEMA;
+using NativeBinarySemaphoreHandle = NativeBinarySemaphore&;
+
+inline constexpr ptrdiff_t kBinarySemaphoreMaxValue =
+ std::numeric_limits<ptrdiff_t>::max() < std::numeric_limits<OS_UINT>::max()
+ ? std::numeric_limits<ptrdiff_t>::max()
+ : std::numeric_limits<OS_UINT>::max();
+
+} // namespace pw::sync::backend
diff --git a/pw_sync_embos/public/pw_sync_embos/counting_semaphore_inline.h b/pw_sync_embos/public/pw_sync_embos/counting_semaphore_inline.h
new file mode 100644
index 0000000..d0b1a8c
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/counting_semaphore_inline.h
@@ -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.
+#pragma once
+
+#include "RTOS.h"
+#include "pw_assert/light.h"
+#include "pw_chrono/system_clock.h"
+#include "pw_chrono_embos/system_clock_constants.h"
+#include "pw_interrupt/context.h"
+#include "pw_sync/counting_semaphore.h"
+
+namespace pw::sync {
+
+inline CountingSemaphore::CountingSemaphore() : native_type_() {
+ OS_CreateCSema(&native_type_, 0);
+}
+
+inline CountingSemaphore::~CountingSemaphore() {
+ OS_DeleteCSema(&native_type_);
+}
+
+inline void CountingSemaphore::acquire() {
+ PW_ASSERT(!interrupt::InInterruptContext());
+ OS_WaitCSema(&native_type_);
+}
+
+inline bool CountingSemaphore::try_acquire() noexcept {
+ return OS_CSemaRequest(&native_type_) != 0;
+}
+
+inline bool CountingSemaphore::try_acquire_until(
+ chrono::SystemClock::time_point until_at_least) {
+ return try_acquire_for(until_at_least - chrono::SystemClock::now());
+}
+
+inline CountingSemaphore::native_handle_type
+CountingSemaphore::native_handle() {
+ return native_type_;
+}
+
+} // namespace pw::sync
diff --git a/pw_sync_embos/public/pw_sync_embos/counting_semaphore_native.h b/pw_sync_embos/public/pw_sync_embos/counting_semaphore_native.h
new file mode 100644
index 0000000..56959b6
--- /dev/null
+++ b/pw_sync_embos/public/pw_sync_embos/counting_semaphore_native.h
@@ -0,0 +1,30 @@
+// 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 <limits>
+
+#include "RTOS.h"
+
+namespace pw::sync::backend {
+
+using NativeCountingSemaphore = OS_CSEMA;
+using NativeCountingSemaphoreHandle = NativeCountingSemaphore&;
+
+inline constexpr ptrdiff_t kCountingSemaphoreMaxValue =
+ std::numeric_limits<ptrdiff_t>::max() < std::numeric_limits<OS_UINT>::max()
+ ? std::numeric_limits<ptrdiff_t>::max()
+ : std::numeric_limits<OS_UINT>::max();
+
+} // namespace pw::sync::backend
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_inline.h b/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_inline.h
new file mode 100644
index 0000000..0179e82
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_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/binary_semaphore_inline.h"
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_native.h b/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_native.h
new file mode 100644
index 0000000..e056b63
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/binary_semaphore_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/binary_semaphore_native.h"
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_inline.h b/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_inline.h
new file mode 100644
index 0000000..aa4ffa6
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_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/counting_semaphore_inline.h"
diff --git a/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_native.h b/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_native.h
new file mode 100644
index 0000000..9b98e24
--- /dev/null
+++ b/pw_sync_embos/public_overrides/pw_sync_backend/counting_semaphore_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/counting_semaphore_native.h"