[magma] Add magma_poll
magma_poll allows the client to handle notification messages while
waiting for semaphores.
Intended to replace magma_wait_semaphores and magma_wait_notification_channel.
Bug:49117
Testability:new tests
Test:
acer:go/magma-tps#L1
Change-Id: I74b5f303475de756bcd1a80bb075fa4f522b8255
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/375421
Commit-Queue: Craig Stout <cstout@google.com>
Reviewed-by: John Bauman <jbauman@google.com>
Testability-Review: John Bauman <jbauman@google.com>
diff --git a/src/graphics/drivers/msd-arm-mali/tests/unit_tests/test_device.cc b/src/graphics/drivers/msd-arm-mali/tests/unit_tests/test_device.cc
index 39bd2f6..5f7ee19 100644
--- a/src/graphics/drivers/msd-arm-mali/tests/unit_tests/test_device.cc
+++ b/src/graphics/drivers/msd-arm-mali/tests/unit_tests/test_device.cc
@@ -177,8 +177,8 @@
magma::Status Wait(uint64_t timeout_ms) override { return MAGMA_STATUS_OK; }
- bool WaitAsync(magma::PlatformPort* platform_port) override {
- return real_semaphore_->WaitAsync(platform_port);
+ bool WaitAsync(magma::PlatformPort* port, uint64_t* key_out) override {
+ return real_semaphore_->WaitAsync(port, key_out);
}
uint64_t id() override { return real_semaphore_->id(); }
bool duplicate_handle(uint32_t* handle_out) override {
diff --git a/src/graphics/drivers/msd-intel-gen/tests/unit_tests/test_device.cc b/src/graphics/drivers/msd-intel-gen/tests/unit_tests/test_device.cc
index 160e561..8b0b36d 100644
--- a/src/graphics/drivers/msd-intel-gen/tests/unit_tests/test_device.cc
+++ b/src/graphics/drivers/msd-intel-gen/tests/unit_tests/test_device.cc
@@ -385,7 +385,7 @@
return wait_return_.load();
}
- bool WaitAsync(magma::PlatformPort* platform_port) override { return false; }
+ bool WaitAsync(magma::PlatformPort* port, uint64_t* key_out) override { return false; }
std::unique_ptr<magma::PlatformSemaphore> sem_ = magma::PlatformSemaphore::Create();
std::unique_ptr<magma::PlatformSemaphore> signal_sem_ = magma::PlatformSemaphore::Create();
diff --git a/src/graphics/lib/magma/include/magma_abi/magma.h b/src/graphics/lib/magma/include/magma_abi/magma.h
index 8b0a2f3..7419eb0 100644
--- a/src/graphics/lib/magma/include/magma_abi/magma.h
+++ b/src/graphics/lib/magma/include/magma_abi/magma.h
@@ -345,7 +345,8 @@
magma_semaphore_t semaphore);
///
-/// \brief Waits for one or all provided semaphores to be signaled. Does not reset any semaphores.
+/// \brief DEPRECATED. Waits for one or all provided semaphores to be signaled. Does not reset any
+/// semaphores.
/// \param semaphores Array of valid semaphores.
/// \param count Number of semaphores in the array.
/// \param timeout_ms Time to wait before returning MAGMA_STATUS_TIMED_OUT.
@@ -390,8 +391,8 @@
magma_connection_t connection);
///
-/// \brief Returns MAGMA_STATUS_OK if a message is available on the notification channel before the
-/// given timeout expires.
+/// \brief DEPRECATED. Returns MAGMA_STATUS_OK if a message is available on the notification channel
+/// before the given timeout expires.
/// \param connection An open connection.
/// \param timeout_ns Time to wait before returning MAGMA_STATUS_TIMED_OUT.
///
@@ -476,6 +477,22 @@
magma_status_t magma_initialize_logging(
magma_handle_t channel);
+///
+/// \brief Waits for at least one of the given items to meet a condition. Does not reset any
+/// semaphores. Results are returned in the items array.
+/// \param items Array of poll items. Type should be either MAGMA_POLL_TYPE_SEMAPHORE or
+/// MAGMA_POLL_TYPE_HANDLE. Condition may be set to MAGMA_POLL_CONDITION_SIGNALED OR
+/// MAGMA_POLL_CONDITION_READABLE. If condition is 0 the item is ignored. Item results are
+/// set to the condition that was satisfied, otherwise 0. If the same item is given twice the
+/// behavior is undefined.
+/// \param count Number of poll items in the array.
+/// \param timeout_ns Time in ns to wait before returning MAGMA_STATUS_TIMED_OUT.
+///
+magma_status_t magma_poll(
+ magma_poll_item_t* items,
+ uint32_t count,
+ uint64_t timeout_ns);
+
#if defined(__cplusplus)
}
#endif
diff --git a/src/graphics/lib/magma/include/magma_abi/magma.json b/src/graphics/lib/magma/include/magma_abi/magma.json
index 6484e59..58950af 100644
--- a/src/graphics/lib/magma/include/magma_abi/magma.json
+++ b/src/graphics/lib/magma/include/magma_abi/magma.json
@@ -1,6 +1,6 @@
{
"magma-interface": {
- "next-free-ordinal": 52,
+ "next-free-ordinal": 53,
"exports": [
{
"ordinal": 4,
@@ -649,7 +649,7 @@
"ordinal": 39,
"name": "magma_wait_semaphores",
"type": "magma_status_t",
- "description": "Waits for one or all provided semaphores to be signaled. Does not reset any semaphores.",
+ "description": "DEPRECATED. Waits for one or all provided semaphores to be signaled. Does not reset any semaphores.",
"arguments": [
{
"name": "semaphores",
@@ -736,7 +736,7 @@
"ordinal": 43,
"name": "magma_wait_notification_channel",
"type": "magma_status_t",
- "description": "Returns MAGMA_STATUS_OK if a message is available on the notification channel before the given timeout expires.",
+ "description": "DEPRECATED. Returns MAGMA_STATUS_OK if a message is available on the notification channel before the given timeout expires.",
"arguments": [
{
"name": "connection",
@@ -898,6 +898,29 @@
"description": "An open connection to the syslog service."
}
]
+ },
+ {
+ "ordinal": 52,
+ "name": "magma_poll",
+ "type": "magma_status_t",
+ "description": "Waits for at least one of the given items to meet a condition. Does not reset any semaphores. Results are returned in the items array.",
+ "arguments": [
+ {
+ "name": "items",
+ "type": "magma_poll_item_t*",
+ "description": "Array of poll items. Type should be either MAGMA_POLL_TYPE_SEMAPHORE or MAGMA_POLL_TYPE_HANDLE. Condition may be set to MAGMA_POLL_CONDITION_SIGNALED OR MAGMA_POLL_CONDITION_READABLE. If condition is 0 the item is ignored. Item results are set to the condition that was satisfied, otherwise 0. If the same item is given twice the behavior is undefined."
+ },
+ {
+ "name": "count",
+ "type": "uint32_t",
+ "description": "Number of poll items in the array."
+ },
+ {
+ "name": "timeout_ns",
+ "type": "uint64_t",
+ "description": "Time in ns to wait before returning MAGMA_STATUS_TIMED_OUT."
+ }
+ ]
}
]
}
diff --git a/src/graphics/lib/magma/include/magma_abi/magma_common_defs.h b/src/graphics/lib/magma/include/magma_abi/magma_common_defs.h
index 8f0f305..ded5a7b 100644
--- a/src/graphics/lib/magma/include/magma_abi/magma_common_defs.h
+++ b/src/graphics/lib/magma/include/magma_abi/magma_common_defs.h
@@ -82,6 +82,13 @@
MAGMA_COHERENCY_DOMAIN_RAM = 1,
};
+enum { MAGMA_POLL_TYPE_SEMAPHORE = 1, MAGMA_POLL_TYPE_HANDLE = 2 };
+
+enum {
+ MAGMA_POLL_CONDITION_READABLE = 1,
+ MAGMA_POLL_CONDITION_SIGNALED = 3,
+};
+
#define MAGMA_SYSMEM_FLAG_PROTECTED (1 << 0)
#define MAGMA_SYSMEM_FLAG_DISPLAY (1 << 1)
@@ -117,6 +124,16 @@
// Corresponds to a zx_handle_t on Fuchsia.
typedef uint32_t magma_handle_t;
+typedef struct magma_poll_item {
+ union {
+ magma_semaphore_t semaphore;
+ magma_handle_t handle;
+ };
+ uint32_t type;
+ uint32_t condition;
+ uint32_t result;
+} magma_poll_item_t;
+
// a buffer plus its associated relocations referenced by a command buffer
struct magma_system_exec_resource {
uint64_t buffer_id;
diff --git a/src/graphics/lib/magma/src/libmagma/magma.cc b/src/graphics/lib/magma/src/libmagma/magma.cc
index 871c496..e1174e7 100644
--- a/src/graphics/lib/magma/src/libmagma/magma.cc
+++ b/src/graphics/lib/magma/src/libmagma/magma.cc
@@ -5,12 +5,14 @@
#include "magma.h"
#include <chrono>
+#include <map>
#include "magma_util/macros.h"
#include "platform_connection_client.h"
#include "platform_device_client.h"
#include "platform_handle.h"
#include "platform_logger.h"
+#include "platform_object.h"
#include "platform_port.h"
#include "platform_semaphore.h"
#include "platform_thread.h"
@@ -385,6 +387,95 @@
return MAGMA_STATUS_OK;
}
+magma_status_t magma_poll(magma_poll_item_t* items, uint32_t count, uint64_t timeout_ns) {
+ // Optimize for simple case
+ if (count == 1 && items[0].type == MAGMA_POLL_TYPE_SEMAPHORE &&
+ items[0].condition == MAGMA_POLL_CONDITION_SIGNALED) {
+ items[0].result = 0;
+ // TODO(fxb/49103) change WaitNoReset to take ns
+ if (!reinterpret_cast<magma::PlatformSemaphore*>(items[0].semaphore)
+ ->WaitNoReset(magma::ns_to_ms(timeout_ns)))
+ return MAGMA_STATUS_TIMED_OUT;
+
+ items[0].result = items[0].condition;
+ return MAGMA_STATUS_OK;
+ }
+
+ std::unique_ptr<magma::PlatformPort> port = magma::PlatformPort::Create();
+ if (!port)
+ return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "Failed to create port");
+
+ // Map of key to item index
+ std::map<uint64_t, uint32_t> map;
+
+ for (uint32_t i = 0; i < count; i++) {
+ items[i].result = 0;
+
+ if (!items[i].condition)
+ continue;
+
+ switch (items[i].type) {
+ case MAGMA_POLL_TYPE_SEMAPHORE: {
+ if (items[i].condition != MAGMA_POLL_CONDITION_SIGNALED)
+ return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Invalid condition for semaphore: 0x%x",
+ items[i].condition);
+
+ auto semaphore = reinterpret_cast<magma::PlatformSemaphore*>(items[i].semaphore);
+ uint64_t key;
+ if (!semaphore->WaitAsync(port.get(), &key))
+ return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "WaitAsync failed");
+
+ map[key] = i;
+ break;
+ }
+
+ case MAGMA_POLL_TYPE_HANDLE: {
+ if (items[i].condition != MAGMA_POLL_CONDITION_READABLE)
+ return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Invalid condition for handle: 0x%x",
+ items[i].condition);
+
+ auto platform_handle = magma::PlatformHandle::Create(items[i].handle);
+ if (!platform_handle)
+ return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "Failed to create platform handle");
+
+ uint64_t key;
+ bool result = platform_handle->WaitAsync(port.get(), &key);
+ platform_handle->release();
+
+ if (!result)
+ return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "WaitAsync failed");
+
+ map[key] = i;
+ break;
+ }
+ }
+ }
+
+ if (map.empty())
+ return DRET_MSG(MAGMA_STATUS_INVALID_ARGS, "Nothing to do");
+
+ // TODO(fxb/49103) change PlatformPort::Wait to take ns
+ uint64_t key;
+ magma::Status status = port->Wait(&key, magma::ns_to_ms(timeout_ns));
+ if (!status)
+ return status.get();
+
+ while (status) {
+ auto iter = map.find(key);
+ if (iter == map.end())
+ return DRET_MSG(MAGMA_STATUS_INTERNAL_ERROR, "Couldn't find key in map: 0x%lx", key);
+
+ uint32_t index = iter->second;
+ DASSERT(index < count);
+ items[index].result = items[index].condition;
+
+ // Check for more events
+ status = port->Wait(&key, 0);
+ }
+
+ return MAGMA_STATUS_OK;
+}
+
magma_status_t magma_export_semaphore(magma_connection_t connection, magma_semaphore_t semaphore,
uint32_t* semaphore_handle_out) {
auto platform_semaphore = reinterpret_cast<magma::PlatformSemaphore*>(semaphore);
diff --git a/src/graphics/lib/magma/src/libmagma_linux/magma.cc b/src/graphics/lib/magma/src/libmagma_linux/magma.cc
index f1e0ff2..942879a 100644
--- a/src/graphics/lib/magma/src/libmagma_linux/magma.cc
+++ b/src/graphics/lib/magma/src/libmagma_linux/magma.cc
@@ -103,6 +103,10 @@
return result_return;
}
+magma_status_t magma_poll(magma_poll_item_t* items, uint32_t count, uint64_t timeout_ns) {
+ return MAGMA_STATUS_UNIMPLEMENTED;
+}
+
void magma_execute_command_buffer_with_resources(magma_connection_t connection, uint32_t context_id,
struct magma_system_command_buffer* command_buffer,
struct magma_system_exec_resource* resources,
diff --git a/src/graphics/lib/magma/src/magma_util/platform/BUILD.gn b/src/graphics/lib/magma/src/magma_util/platform/BUILD.gn
index e3e62e1..437d207 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/BUILD.gn
+++ b/src/graphics/lib/magma/src/magma_util/platform/BUILD.gn
@@ -108,10 +108,15 @@
public_configs = [ ":platform_include_config" ]
sources = [ "platform_handle.h" ]
+
+ public_deps = [ ":port_header" ]
}
source_set("handle") {
- public_deps = [ ":handle_header" ]
+ public_deps = [
+ ":handle_header",
+ ":port",
+ ]
if (is_fuchsia) {
deps = [ "zircon:handle" ]
diff --git a/src/graphics/lib/magma/src/magma_util/platform/platform_handle.h b/src/graphics/lib/magma/src/magma_util/platform/platform_handle.h
index 7e481fd..117cffd 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/platform_handle.h
+++ b/src/graphics/lib/magma/src/magma_util/platform/platform_handle.h
@@ -7,6 +7,8 @@
#include <memory>
+#include "platform_port.h"
+
namespace magma {
class PlatformHandle {
@@ -17,6 +19,11 @@
virtual bool GetCount(uint32_t* count_out) = 0;
virtual uint32_t release() = 0;
+ // Registers an async wait delivered on the given |port| when the given handle is readable,
+ // or if the handle has a peer and the peer is closed.
+ // On success returns true and |key_out| is set.
+ virtual bool WaitAsync(PlatformPort* port, uint64_t* key_out) = 0;
+
static bool duplicate_handle(uint32_t handle_in, uint32_t* handle_out);
static std::unique_ptr<PlatformHandle> Create(uint32_t handle);
diff --git a/src/graphics/lib/magma/src/magma_util/platform/platform_semaphore.h b/src/graphics/lib/magma/src/magma_util/platform/platform_semaphore.h
index d999df2..5bd2aad 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/platform_semaphore.h
+++ b/src/graphics/lib/magma/src/magma_util/platform/platform_semaphore.h
@@ -68,7 +68,13 @@
// Registers an async wait delivered on the given port when this semaphore is signalled.
// Note that a port wait completion will not autoreset the semaphore.
- virtual bool WaitAsync(PlatformPort* platform_port) = 0;
+ // On success returns true and |key_out| is set.
+ virtual bool WaitAsync(PlatformPort* port, uint64_t* key_out) = 0;
+
+ bool WaitAsync(PlatformPort* port) {
+ uint64_t key;
+ return WaitAsync(port, &key);
+ }
};
} // namespace magma
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/BUILD.gn b/src/graphics/lib/magma/src/magma_util/platform/zircon/BUILD.gn
index 1a4dba9..8fbca83 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/BUILD.gn
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/BUILD.gn
@@ -225,12 +225,16 @@
]
public_deps = [
+ ":port",
"$magma_build_root/src/magma_util:macros",
"$zircon_build_root/public/lib/zx",
"..:handle_header",
]
- deps = [ "$magma_build_root/src/magma_util:macros" ]
+ deps = [
+ "$magma_build_root/src/magma_util:macros",
+ "..:object",
+ ]
}
source_set("iommu") {
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.cc b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.cc
index 6437abb..72d3dc5 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.cc
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.cc
@@ -6,6 +6,9 @@
#include <lib/zx/handle.h>
+#include "platform_object.h"
+#include "zircon_platform_port.h"
+
namespace magma {
bool ZirconPlatformHandle::GetCount(uint32_t* count_out) {
@@ -19,6 +22,20 @@
return true;
}
+bool ZirconPlatformHandle::WaitAsync(PlatformPort* port, uint64_t* key_out) {
+ if (!PlatformObject::IdFromHandle(get(), key_out))
+ return DRET_MSG(false, "IdFromHandle failed");
+
+ auto zircon_port = static_cast<ZirconPlatformPort*>(port);
+ zx_status_t status =
+ handle_.wait_async(zircon_port->zx_port(), *key_out,
+ ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, ZX_WAIT_ASYNC_ONCE);
+ if (status != ZX_OK)
+ return DRETF(false, "wait_async failed: %d", status);
+
+ return true;
+}
+
// static
bool PlatformHandle::duplicate_handle(uint32_t handle_in, uint32_t* handle_out) {
zx_status_t status = zx_handle_duplicate(handle_in, ZX_RIGHT_SAME_RIGHTS, handle_out);
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.h b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.h
index 6a8562a..eb6484f 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.h
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_handle.h
@@ -20,6 +20,8 @@
bool GetCount(uint32_t* count_out) override;
+ bool WaitAsync(PlatformPort* port, uint64_t* key_out) override;
+
uint32_t release() override { return handle_.release(); }
zx_handle_t get() { return handle_.get(); }
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_port.cc b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_port.cc
index 42325f7..99af079 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_port.cc
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_port.cc
@@ -19,8 +19,11 @@
zx_port_packet_t packet;
zx_status_t status =
port_.wait(zx::deadline_after(zx::duration(magma::ms_to_signed_ns(timeout_ms))), &packet);
- if (status == ZX_ERR_TIMED_OUT)
- return DRET_MSG(MAGMA_STATUS_TIMED_OUT, "port wait timed out");
+ if (status == ZX_ERR_TIMED_OUT) {
+ return timeout_ms == 0 ? MAGMA_STATUS_TIMED_OUT
+ : DRET_MSG(MAGMA_STATUS_TIMED_OUT, "port wait timed out: timeout_ms %lu",
+ timeout_ms);
+ }
DLOG("port received key 0x%" PRIx64 " status %d", packet.key, status);
@@ -31,6 +34,9 @@
// Port has been closed.
port_.reset();
return MAGMA_STATUS_INTERNAL_ERROR;
+ } else if (packet.type == ZX_PKT_TYPE_SIGNAL_ONE &&
+ packet.signal.observed == ZX_CHANNEL_PEER_CLOSED) {
+ return DRET(MAGMA_STATUS_CONNECTION_LOST);
}
*key_out = packet.key;
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.cc b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.cc
index 1b6c320..5d27839 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.cc
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.cc
@@ -45,15 +45,19 @@
return status;
}
-bool ZirconPlatformSemaphore::WaitAsync(PlatformPort* platform_port) {
+bool ZirconPlatformSemaphore::WaitAsync(PlatformPort* port, uint64_t* key_out) {
TRACE_DURATION("magma:sync", "semaphore wait async", "id", koid_);
TRACE_FLOW_BEGIN("magma:sync", "semaphore wait async", koid_);
- auto port = static_cast<ZirconPlatformPort*>(platform_port);
- zx_status_t status = event_.wait_async(port->zx_port(), id(), zx_signal(), ZX_WAIT_ASYNC_ONCE);
+ auto zircon_port = static_cast<ZirconPlatformPort*>(port);
+
+ uint64_t key = id();
+ zx_status_t status =
+ event_.wait_async(zircon_port->zx_port(), key, zx_signal(), ZX_WAIT_ASYNC_ONCE);
if (status != ZX_OK)
return DRETF(false, "wait_async failed: %d", status);
+ *key_out = key;
return true;
}
diff --git a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.h b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.h
index 8a52f60..f3cdf8f 100644
--- a/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.h
+++ b/src/graphics/lib/magma/src/magma_util/platform/zircon/zircon_platform_semaphore.h
@@ -39,7 +39,7 @@
magma::Status WaitNoReset(uint64_t timeout_ms) override;
magma::Status Wait(uint64_t timeout_ms) override;
- bool WaitAsync(PlatformPort* platform_port) override;
+ bool WaitAsync(PlatformPort* port, uint64_t* key_out) override;
zx_handle_t zx_handle() const { return event_.get(); }
diff --git a/src/graphics/lib/magma/tests/integration/test_magma_abi.cc b/src/graphics/lib/magma/tests/integration/test_magma_abi.cc
index 56a41a1..2e126b6 100644
--- a/src/graphics/lib/magma/tests/integration/test_magma_abi.cc
+++ b/src/graphics/lib/magma/tests/integration/test_magma_abi.cc
@@ -32,6 +32,7 @@
inline uint64_t page_size() { return sysconf(_SC_PAGESIZE); }
+inline constexpr int64_t ms_to_ns(int64_t ms) { return ms * 1000000ull; }
} // namespace
class TestConnection {
@@ -286,6 +287,149 @@
}
}
+ void PollWithNotificationChannel(uint32_t semaphore_count) {
+ ASSERT_TRUE(connection_);
+
+ std::vector<magma_poll_item_t> items;
+
+ for (uint32_t i = 0; i < semaphore_count; i++) {
+ magma_semaphore_t semaphore;
+ ASSERT_EQ(MAGMA_STATUS_OK, magma_create_semaphore(connection_, &semaphore));
+
+ items.push_back({.semaphore = semaphore,
+ .type = MAGMA_POLL_TYPE_SEMAPHORE,
+ .condition = MAGMA_POLL_CONDITION_SIGNALED});
+ }
+
+ items.push_back({
+ .handle = magma_get_notification_channel_handle(connection_),
+ .type = MAGMA_POLL_TYPE_HANDLE,
+ .condition = MAGMA_POLL_CONDITION_READABLE,
+ });
+
+ constexpr int64_t kTimeoutNs = ms_to_ns(100);
+ auto start = std::chrono::steady_clock::now();
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, magma_poll(items.data(), items.size(), kTimeoutNs));
+ EXPECT_LE(kTimeoutNs, std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count());
+
+ magma_signal_semaphore(items[0].semaphore);
+
+ EXPECT_EQ(MAGMA_STATUS_OK, magma_poll(items.data(), items.size(), 0));
+ EXPECT_EQ(items[0].result, items[0].condition);
+ EXPECT_EQ(items[1].result, 0u);
+
+ magma_reset_semaphore(items[0].semaphore);
+
+ start = std::chrono::steady_clock::now();
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, magma_poll(items.data(), items.size(), kTimeoutNs));
+ EXPECT_LE(kTimeoutNs, std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count());
+
+ for (uint32_t i = 0; i < semaphore_count; i++) {
+ magma_signal_semaphore(items[i].semaphore);
+ }
+
+ EXPECT_EQ(MAGMA_STATUS_OK, magma_poll(items.data(), items.size(), 0));
+
+ for (uint32_t i = 0; i < items.size(); i++) {
+ if (i < items.size() - 1) {
+ EXPECT_EQ(items[i].result, items[i].condition);
+ } else {
+ // Notification channel
+ EXPECT_EQ(items[i].result, 0u);
+ }
+ }
+
+ for (uint32_t i = 0; i < semaphore_count; i++) {
+ magma_release_semaphore(connection_, items[i].semaphore);
+ }
+ }
+
+ void PollWithTestChannel() {
+#ifdef __Fuchsia__
+ ASSERT_TRUE(connection_);
+
+ zx::channel local, remote;
+ ASSERT_EQ(ZX_OK, zx::channel::create(0 /* flags */, &local, &remote));
+
+ magma_semaphore_t semaphore;
+ ASSERT_EQ(MAGMA_STATUS_OK, magma_create_semaphore(connection_, &semaphore));
+
+ std::vector<magma_poll_item_t> items;
+ items.push_back({.semaphore = semaphore,
+ .type = MAGMA_POLL_TYPE_SEMAPHORE,
+ .condition = MAGMA_POLL_CONDITION_SIGNALED});
+ items.push_back({
+ .handle = local.get(),
+ .type = MAGMA_POLL_TYPE_HANDLE,
+ .condition = MAGMA_POLL_CONDITION_READABLE,
+ });
+
+ constexpr int64_t kTimeoutNs = ms_to_ns(100);
+ auto start = std::chrono::steady_clock::now();
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, magma_poll(items.data(), items.size(), kTimeoutNs));
+ EXPECT_LE(kTimeoutNs, std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count());
+
+ magma_signal_semaphore(semaphore);
+
+ EXPECT_EQ(MAGMA_STATUS_OK, magma_poll(items.data(), items.size(), 0));
+ EXPECT_EQ(items[0].result, items[0].condition);
+ EXPECT_EQ(items[1].result, 0u);
+
+ magma_reset_semaphore(semaphore);
+
+ start = std::chrono::steady_clock::now();
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, magma_poll(items.data(), items.size(), kTimeoutNs));
+ EXPECT_LE(kTimeoutNs, std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count());
+
+ uint32_t dummy;
+ EXPECT_EQ(ZX_OK, remote.write(0 /* flags */, &dummy, sizeof(dummy), nullptr /* handles */,
+ 0 /* num_handles*/));
+
+ EXPECT_EQ(MAGMA_STATUS_OK, magma_poll(items.data(), items.size(), 0));
+ EXPECT_EQ(items[0].result, 0u);
+ EXPECT_EQ(items[1].result, items[1].condition);
+
+ magma_signal_semaphore(semaphore);
+
+ EXPECT_EQ(MAGMA_STATUS_OK, magma_poll(items.data(), items.size(), 0));
+ EXPECT_EQ(items[0].result, items[0].condition);
+ EXPECT_EQ(items[1].result, items[1].condition);
+#else
+ GTEST_SKIP();
+#endif
+ }
+
+ void PollChannelClosed() {
+#ifdef __Fuchsia__
+ ASSERT_TRUE(connection_);
+
+ zx::channel local, remote;
+ ASSERT_EQ(ZX_OK, zx::channel::create(0 /* flags */, &local, &remote));
+
+ std::vector<magma_poll_item_t> items;
+ items.push_back({
+ .handle = local.get(),
+ .type = MAGMA_POLL_TYPE_HANDLE,
+ .condition = MAGMA_POLL_CONDITION_READABLE,
+ });
+
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, magma_poll(items.data(), items.size(), 0));
+
+ remote.reset();
+ EXPECT_EQ(MAGMA_STATUS_CONNECTION_LOST, magma_poll(items.data(), items.size(), 0));
+#else
+ GTEST_SKIP();
+#endif
+ }
+
void SemaphoreExport(uint32_t* handle_out, uint64_t* id_out) {
ASSERT_NE(connection_, nullptr);
magma_semaphore_t semaphore;
@@ -646,6 +790,16 @@
TEST(MagmaAbi, ImmediateCommands) { TestConnection().ImmediateCommands(); }
+TEST(MagmaAbi, PollWithNotificationChannel) {
+ TestConnection().PollWithNotificationChannel(1);
+ TestConnection().PollWithNotificationChannel(2);
+ TestConnection().PollWithNotificationChannel(3);
+}
+
+TEST(MagmaAbi, PollWithTestChannel) { TestConnection().PollWithTestChannel(); }
+
+TEST(MagmaAbi, PollChannelClosed) { TestConnection().PollChannelClosed(); }
+
TEST(MagmaAbi, ImageFormat) {
TestConnection test;
test.ImageFormat();
diff --git a/src/graphics/lib/magma/tests/mock/mock_magma_system.cc b/src/graphics/lib/magma/tests/mock/mock_magma_system.cc
index 50b7093..f83b635 100644
--- a/src/graphics/lib/magma/tests/mock/mock_magma_system.cc
+++ b/src/graphics/lib/magma/tests/mock/mock_magma_system.cc
@@ -365,3 +365,7 @@
magma_status_t magma_initialize_logging(magma_handle_t channel) {
return MAGMA_STATUS_UNIMPLEMENTED;
}
+
+magma_status_t magma_poll(magma_poll_item_t* items, uint32_t count, uint64_t timeout_ns) {
+ return MAGMA_STATUS_UNIMPLEMENTED;
+}
diff --git a/src/graphics/lib/magma/tests/unit_tests/test_platform_port.cc b/src/graphics/lib/magma/tests/unit_tests/test_platform_port.cc
index 65081d6..996baf5 100644
--- a/src/graphics/lib/magma/tests/unit_tests/test_platform_port.cc
+++ b/src/graphics/lib/magma/tests/unit_tests/test_platform_port.cc
@@ -10,6 +10,10 @@
#include "platform_port.h"
#include "platform_semaphore.h"
+#ifdef __Fuchsia__
+#include <lib/zx/channel.h>
+#endif
+
namespace {
class TestPort {
@@ -92,8 +96,53 @@
}));
thread->join();
}
+
+ static void TestHandle() {
+#ifdef __Fuchsia__
+ zx::channel local, remote;
+ ASSERT_EQ(ZX_OK, zx::channel::create(0 /*flags*/, &local, &remote));
+
+ auto handle = magma::PlatformHandle::Create(local.release());
+ ASSERT_TRUE(handle);
+
+ auto port = magma::PlatformPort::Create();
+ ASSERT_TRUE(port);
+
+ uint64_t handle_key;
+ EXPECT_TRUE(handle->WaitAsync(port.get(), &handle_key));
+
+ uint64_t key;
+ EXPECT_EQ(MAGMA_STATUS_TIMED_OUT, port->Wait(&key, 0).get());
+
+ uint32_t dummy;
+ EXPECT_EQ(ZX_OK, remote.write(0 /* flags */, &dummy, sizeof(dummy), nullptr /* handles */,
+ 0 /* num_handles*/));
+
+ // Close the peer
+ remote.reset();
+
+ EXPECT_EQ(MAGMA_STATUS_OK, port->Wait(&key, 0).get());
+ EXPECT_EQ(handle_key, key);
+
+ local.reset(handle->release());
+
+ uint32_t actual_bytes;
+ EXPECT_EQ(ZX_OK, local.read(0 /* flags */, &dummy, nullptr /*handles*/, sizeof(dummy),
+ 0 /*num_handles*/, &actual_bytes, nullptr /*actual_handles*/));
+
+ handle = magma::PlatformHandle::Create(local.release());
+
+ EXPECT_TRUE(handle->WaitAsync(port.get(), &handle_key));
+
+ EXPECT_EQ(MAGMA_STATUS_CONNECTION_LOST, port->Wait(&key, 0).get());
+#else
+ GTEST_SKIP();
+#endif
+ }
};
} // namespace
TEST(PlatformPort, Test) { TestPort::Test(); }
+
+TEST(PlatformPort, Handle) { TestPort::TestHandle(); }