blob: 1f4da3ec8ce3b4bf91340c46d9b1f8e783547a51 [file] [log] [blame]
// Copyright 2016 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 <assert.h>
#include <stdio.h>
#include <threads.h>
#include <zx/channel.h>
#include <zx/event.h>
#include <zx/handle.h>
#include <zx/port.h>
#include <fbl/type_support.h>
#include <zircon/syscalls/port.h>
#include <unistd.h>
#include <unittest/unittest.h>
static bool basic_test() {
// Test that"
// 1- handles starts with the ZX_SIGNAL_LAST_HANDLE active.
// 2- the signal deactives on duplication.
// 3- the signal comes back on closing the duplicated handle.
// 4- the ZX_SIGNAL_LAST_HANDLE cannot be touched with zx_object_signal().
BEGIN_TEST;
zx::event event;
ASSERT_EQ(zx::event::create(0u, &event), ZX_OK);
zx_signals_t observed = 0u;
EXPECT_EQ(
event.wait_one(ZX_SIGNAL_LAST_HANDLE, ZX_TIME_INFINITE, &observed), ZX_OK);
EXPECT_EQ(observed, ZX_SIGNAL_LAST_HANDLE);
zx::event dup;
EXPECT_EQ(event.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup), ZX_OK);
EXPECT_EQ(event.wait_one(ZX_SIGNAL_LAST_HANDLE, 0u, &observed), ZX_ERR_TIMED_OUT);
EXPECT_EQ(observed, 0u);
dup.reset();
EXPECT_EQ(
event.wait_one(ZX_SIGNAL_LAST_HANDLE, ZX_TIME_INFINITE, &observed), ZX_OK);
EXPECT_EQ(observed, ZX_SIGNAL_LAST_HANDLE);
EXPECT_EQ(event.signal(ZX_SIGNAL_LAST_HANDLE, 0), ZX_ERR_INVALID_ARGS);
END_TEST;
}
static bool replace_test() {
// Test that:
// 1- replacing the handle keeps the ZX_SIGNAL_LAST_HANDLE signal.
// 2- replacing a duplicate does not spuriosly signal ZX_SIGNAL_LAST_HANDLE.
// 3- closing the replacement does signal ZX_SIGNAL_LAST_HANDLE.
// Note: we rely on a port to detect the edge transition, if any.
BEGIN_TEST;
zx::event old_ev;
ASSERT_EQ(zx::event::create(0u, &old_ev), ZX_OK);
zx::event new_ev;
EXPECT_EQ(old_ev.replace(ZX_RIGHT_SAME_RIGHTS, &new_ev), ZX_OK);
zx_signals_t observed = 0u;
EXPECT_EQ(
new_ev.wait_one(ZX_SIGNAL_LAST_HANDLE, ZX_TIME_INFINITE, &observed), ZX_OK);
EXPECT_EQ(observed, ZX_SIGNAL_LAST_HANDLE);
zx::event dup;
EXPECT_EQ(new_ev.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup), ZX_OK);
zx::port port;
ASSERT_EQ(zx::port::create(0, &port), ZX_OK);
EXPECT_EQ(new_ev.wait_async(
port, 1u, ZX_SIGNAL_LAST_HANDLE, ZX_WAIT_ASYNC_ONCE), ZX_OK);
zx_port_packet_t packet = {};
EXPECT_EQ(port.wait(0ull, &packet, 0u), ZX_ERR_TIMED_OUT);
zx::event new_dup;
EXPECT_EQ(dup.replace(ZX_RIGHT_SAME_RIGHTS, &new_dup), ZX_OK);
EXPECT_EQ(port.wait(0ull, &packet, 0u), ZX_ERR_TIMED_OUT);
new_dup.reset();
EXPECT_EQ(port.wait(ZX_TIME_INFINITE, &packet, 0u), ZX_OK);
EXPECT_EQ(packet.type, ZX_PKT_TYPE_SIGNAL_ONE);
EXPECT_EQ(packet.signal.observed, ZX_SIGNAL_LAST_HANDLE);
END_TEST;
}
static bool channel_test() {
// Test that:
// 1- Sending/receiving a duplicated object never triggers ZX_SIGNAL_LAST_HANDLE. The
// handle count is still 2, even though one handle is not accessible to
// any process.
// 2- Sending an object and closing the send side of a channel does not trigger
// ZX_SIGNAL_LAST_HANDLE.
// 3- Closing the receive side of #2 does trigger ZX_SIGNAL_LAST_HANDLE.
BEGIN_TEST;
zx::event event;
ASSERT_EQ(zx::event::create(0u, &event), ZX_OK);
zx::channel channel[2];
ASSERT_EQ(zx::channel::create(0u, &channel[0], &channel[1]), ZX_OK);
zx::port port;
ASSERT_EQ(zx::port::create(0, &port), ZX_OK);
zx_handle_t dup_ev;
EXPECT_EQ(zx_handle_duplicate(event.get(), ZX_RIGHT_SAME_RIGHTS, &dup_ev), ZX_OK);
ASSERT_EQ(event.wait_async(
port, 1u, ZX_SIGNAL_LAST_HANDLE, ZX_WAIT_ASYNC_ONCE), ZX_OK);
uint32_t actual_b;
uint32_t actual_h;
zx_port_packet_t packet = {};
for (int ix = 0; ix != 4; ++ix) {
ASSERT_EQ(channel[0].write(0u, nullptr, 0u, &dup_ev, 1u), ZX_OK);
dup_ev = 0u;
EXPECT_EQ(port.wait(0ull, &packet, 0u), ZX_ERR_TIMED_OUT);
ASSERT_EQ(channel[1].read(
0u, nullptr, 0, &actual_b, &dup_ev, 1u, &actual_h), ZX_OK);
EXPECT_EQ(port.wait(0ull, &packet, 0u), ZX_ERR_TIMED_OUT);
}
ASSERT_EQ(channel[0].write(0u, nullptr, 0u, &dup_ev, 1u), ZX_OK);
channel[0].reset();
EXPECT_EQ(port.wait(0ull, &packet, 0u), ZX_ERR_TIMED_OUT);
channel[1].reset();
EXPECT_EQ(port.wait(ZX_TIME_INFINITE, &packet, 0u), ZX_OK);
EXPECT_EQ(packet.type, ZX_PKT_TYPE_SIGNAL_ONE);
EXPECT_EQ(packet.signal.observed, ZX_SIGNAL_LAST_HANDLE);
END_TEST;
}
BEGIN_TEST_CASE(last_handle)
RUN_TEST(basic_test)
RUN_TEST(replace_test)
RUN_TEST(channel_test)
END_TEST_CASE(last_handle)
int main(int argc, char** argv) {
bool success = unittest_run_all_tests(argc, argv);
return success ? 0 : -1;
}