[fuchsia] Implement futex directly on zircon syscalls.
PlatformFutex won't be available in the Fuchsia SDK.
Change-Id: I78343e2f1785569c1fc44aa33d40d3315057ea0e
diff --git a/src/util/BUILD.gn b/src/util/BUILD.gn
index 89b2987..2ab6fb7 100644
--- a/src/util/BUILD.gn
+++ b/src/util/BUILD.gn
@@ -102,18 +102,15 @@
"vma.c",
]
- deps = [
- "$magma_build_root/src/magma_util",
- ]
+ deps = []
if (current_os == "fuchsia") {
sources += [
- "futex_fuchsia.cpp",
+ "futex_fuchsia.c",
"os_dirent_fuchsia.cpp",
]
deps += [
"$mesa_build_root/src/os",
- "$magma_build_root/src/magma_util/platform:futex",
"//zircon/public/lib/zx",
"//zircon/public/lib/zxio",
]
diff --git a/src/util/futex_fuchsia.c b/src/util/futex_fuchsia.c
new file mode 100644
index 0000000..8e2c49a
--- /dev/null
+++ b/src/util/futex_fuchsia.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2019 Google, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "futex.h"
+#include "os/fuchsia.h"
+#include "util/timespec.h"
+#include <assert.h>
+#include <errno.h>
+#include <zircon/syscalls.h>
+
+static_assert(sizeof(zx_futex_t) == sizeof(uint32_t), "futex type incompatible size");
+
+enum WaitResult { AWOKE, TIMED_OUT, RETRY };
+
+static inline bool Wake(uint32_t* value_ptr, int32_t wake_count)
+{
+ zx_status_t status;
+ if ((status = zx_futex_wake((zx_futex_t*)value_ptr, wake_count)) != ZX_OK) {
+ FUCHSIA_DLOG("zx_futex_wake failed: %d", status);
+ return false;
+ }
+ return true;
+}
+
+static inline bool Wait(uint32_t* value_ptr, int32_t current_value, uint64_t timeout_ns,
+ enum WaitResult* result_out)
+{
+ const zx_time_t deadline =
+ (timeout_ns == UINT64_MAX) ? ZX_TIME_INFINITE : zx_deadline_after(timeout_ns);
+ zx_status_t status =
+ zx_futex_wait((zx_futex_t*)value_ptr, current_value, ZX_HANDLE_INVALID, deadline);
+ switch (status) {
+ case ZX_OK:
+ *result_out = AWOKE;
+ break;
+ case ZX_ERR_TIMED_OUT:
+ *result_out = TIMED_OUT;
+ break;
+ case ZX_ERR_BAD_STATE:
+ *result_out = RETRY;
+ break;
+ default:
+ FUCHSIA_DLOG("zx_futex_wait returned: %d", status);
+ return false;
+ }
+ return true;
+}
+
+int futex_wake(uint32_t* addr, int count)
+{
+ if (!Wake(addr, count)) {
+ FUCHSIA_DLOG("PlatformFutex::Wake failed");
+ return -1;
+ }
+ return 0;
+}
+
+int futex_wait(uint32_t* addr, int32_t value, const struct timespec* timeout)
+{
+ uint64_t timeout_ns;
+ if (timeout == NULL) {
+ timeout_ns = UINT64_MAX;
+ } else {
+ timeout_ns = timespec_to_nsec(timeout);
+ }
+
+ enum WaitResult result;
+ if (!Wait(addr, value, timeout_ns, &result)) {
+ FUCHSIA_DLOG("PlatformFutex::WaitForever failed");
+ return -EINVAL;
+ }
+ switch (result) {
+ case RETRY:
+ return -EAGAIN;
+ case TIMED_OUT:
+ return -ETIMEDOUT;
+ default:
+ break;
+ }
+ assert(result == AWOKE);
+ return 0;
+}
diff --git a/src/util/futex_fuchsia.cpp b/src/util/futex_fuchsia.cpp
deleted file mode 100644
index ed36e67..0000000
--- a/src/util/futex_fuchsia.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright © 2019 Google, LLC
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include "futex.h"
-#include "platform_futex.h"
-#include <assert.h>
-#include <errno.h>
-#include "os/fuchsia.h"
-
-int futex_wake(uint32_t* addr, int count)
-{
- if (!magma::PlatformFutex::Wake(addr, count)) {
- FUCHSIA_DLOG("PlatformFutex::Wake failed");
- return -1;
- }
- return 0;
-}
-
-int futex_wait(uint32_t* addr, int32_t value, const struct timespec* timeout)
-{
- // Timeouts not implemented.
- assert(timeout == nullptr);
- magma::PlatformFutex::WaitResult result;
- if (!magma::PlatformFutex::WaitForever(addr, value, &result)) {
- FUCHSIA_DLOG("PlatformFutex::WaitForever failed");
- return -EINVAL;
- }
- if (result == magma::PlatformFutex::WaitResult::RETRY)
- return -EAGAIN;
- assert(result == magma::PlatformFutex::WaitResult::AWOKE);
- return 0;
-}
diff --git a/src/util/tests/futex/BUILD.gn b/src/util/tests/futex/BUILD.gn
new file mode 100644
index 0000000..36825f7
--- /dev/null
+++ b/src/util/tests/futex/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright 2019 Google, LLC
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+import("../../../../mesa.gni")
+
+mesa_source_set("futex") {
+ testonly = true
+
+ sources = [
+ "test_futex.cpp",
+ ]
+
+ deps = [ "$mesa_build_root/src/util" ]
+
+ if (is_fuchsia) {
+ deps += [
+ "$mesa_build_root/src/os",
+ "//third_party/googletest:gtest",
+ ]
+ }
+}
diff --git a/src/util/tests/futex/test_futex.cpp b/src/util/tests/futex/test_futex.cpp
new file mode 100644
index 0000000..ba37562
--- /dev/null
+++ b/src/util/tests/futex/test_futex.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2019 Google, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+#include "util/futex.h"
+#include "gtest/gtest.h"
+
+TEST(Futex, Retry)
+{
+ uint32_t value = 0;
+ EXPECT_EQ(-EAGAIN, futex_wait(&value, value + 1, NULL));
+}
+
+TEST(Futex, Timeout)
+{
+ uint32_t value = 0;
+
+ auto start = std::chrono::high_resolution_clock::now();
+
+ static constexpr uint32_t kTimeoutMs = 100;
+ struct timespec timeout = {
+ .tv_sec = 0,
+ .tv_nsec = kTimeoutMs * 1000000,
+ };
+ EXPECT_EQ(-ETIMEDOUT, futex_wait(&value, value, &timeout));
+
+ auto end = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double, std::milli> elapsed = end - start;
+
+ EXPECT_GT(elapsed.count(), kTimeoutMs);
+}
+
+TEST(Futex, WaitAndWake)
+{
+ constexpr int kResultNotReady = 1;
+ static std::atomic<int> result = kResultNotReady;
+ static uint32_t value;
+
+ std::thread thread([]() {
+ int r = futex_wait(&value, value, NULL);
+ result.store(r);
+ });
+
+ int check = kResultNotReady;
+
+ for (int retry = 0; retry < 10; retry++) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ futex_wake(&value, 1);
+ check = result.load();
+ if (check != kResultNotReady) {
+ thread.join();
+ break;
+ }
+ }
+
+ EXPECT_EQ(check, 0);
+}
diff --git a/tests/BUILD.gn b/tests/BUILD.gn
index 7261314..69150c7 100644
--- a/tests/BUILD.gn
+++ b/tests/BUILD.gn
@@ -40,6 +40,7 @@
"unit_tests",
"$mesa_build_root/src/util/tests/os_dirent",
"$mesa_build_root/src/util/tests/inflight_list",
+ "$mesa_build_root/src/util/tests/futex",
"//third_party/googletest:gtest",
]
}