| // Copyright 2020 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/lib/fuchsia-async/cpp/executor.h" | |
| #include <lib/async/receiver.h> | |
| #include <lib/async/task.h> | |
| #include <lib/async/time.h> | |
| #include <lib/async/trap.h> | |
| #include <lib/async/wait.h> | |
| #include <gtest/gtest.h> | |
| #ifdef __Fuchsia__ | |
| #include <zircon/syscalls.h> | |
| #endif | |
| namespace fuchsia_async { | |
| namespace testing { | |
| TEST(FuchsiaAsync, CanCreateAndExitLoop) { Executor executor; } | |
| TEST(FuchsiaAsync, SomeOperationsAreUnsupported) { | |
| Executor executor; | |
| auto* dispatcher = executor.dispatcher(); | |
| EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_queue_packet(dispatcher, nullptr, nullptr)); | |
| EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, async_set_guest_bell_trap(dispatcher, nullptr, 0, 0, 0)); | |
| } | |
| template <class F> | |
| void PostTask(Executor* executor, F impl) { | |
| struct Task { | |
| async_task_t task; | |
| F impl; | |
| static void Handler(async_dispatcher_t* dispatcher, async_task_t* task, zx_status_t status) { | |
| auto* t = reinterpret_cast<Task*>(task); | |
| t->impl(); | |
| delete t; | |
| } | |
| }; | |
| Task* task = new Task{{ | |
| ASYNC_STATE_INIT, | |
| Task::Handler, | |
| async_now(executor->dispatcher()), | |
| }, | |
| std::move(impl)}; | |
| EXPECT_EQ(ZX_OK, async_post_task(executor->dispatcher(), &task->task)); | |
| } | |
| TEST(FuchsiaAsync, CanPostTask) { | |
| Executor executor; | |
| PostTask(&executor, [&executor]() { executor.Quit(); }); | |
| executor.RunSinglethreaded(); | |
| } | |
| template <class F> | |
| void PostWait(Executor* executor, zx_handle_t handle, zx_signals_t trigger, F impl) { | |
| struct Wait { | |
| async_wait_t wait; | |
| F impl; | |
| static void Handler(async_dispatcher_t* dispatcher, async_wait_t* wait, zx_status_t status, | |
| const zx_packet_signal_t* signal) { | |
| auto* w = reinterpret_cast<Wait*>(wait); | |
| w->impl(status, signal); | |
| delete w; | |
| } | |
| }; | |
| Wait* wait = new Wait{{ASYNC_STATE_INIT, Wait::Handler, handle, trigger, 0}, std::move(impl)}; | |
| EXPECT_EQ(ZX_OK, async_begin_wait(executor->dispatcher(), &wait->wait)); | |
| } | |
| // TODO: make this available for host also | |
| #ifdef __Fuchsia__ | |
| TEST(FuchsiaAsync, CanWaitForRead) { | |
| Executor executor; | |
| zx_handle_t a, b; | |
| ASSERT_EQ(ZX_OK, zx_channel_create(0, &a, &b)); | |
| fprintf(stderr, "made channels %u %u\n", a, b); | |
| bool write_queued = false; | |
| PostWait(&executor, b, ZX_CHANNEL_READABLE, | |
| [&executor, &write_queued](zx_status_t status, const zx_packet_signal_t* signal) { | |
| EXPECT_EQ(true, write_queued); | |
| EXPECT_EQ(ZX_OK, status); | |
| EXPECT_TRUE((signal->observed & ZX_CHANNEL_READABLE) != 0); | |
| executor.Quit(); | |
| }); | |
| PostTask(&executor, [a, &write_queued]() { | |
| EXPECT_EQ(false, write_queued); | |
| fprintf(stderr, "write to channel %u\n", a); | |
| ASSERT_EQ(ZX_OK, zx_channel_write(a, 0, nullptr, 0, nullptr, 0)); | |
| write_queued = true; | |
| }); | |
| executor.RunSinglethreaded(); | |
| zx_handle_close(a); | |
| zx_handle_close(b); | |
| } | |
| #endif | |
| } // namespace testing | |
| } // namespace fuchsia_async |