blob: 0f52c9e732981e093c3e7d7062fdd735d1f21b6e [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 <mx/channel.h>
#include <mx/event.h>
#include <mx/handle.h>
#include <mx/port.h>
#include <fbl/type_support.h>
#include <magenta/syscalls/port.h>
#include <unistd.h>
#include <unittest/unittest.h>
static bool basic_test() {
// Test that"
// 1- handles starts with the MX_SIGNAL_LAST_HANDLE active.
// 2- the signal deactives on duplication.
// 3- the signal comes back on closing the duplicated handle.
// 4- the MX_SIGNAL_LAST_HANDLE cannot be touched with mx_object_signal().
BEGIN_TEST;
mx::event event;
ASSERT_EQ(mx::event::create(0u, &event), MX_OK);
mx_signals_t observed = 0u;
EXPECT_EQ(
event.wait_one(MX_SIGNAL_LAST_HANDLE, MX_TIME_INFINITE, &observed), MX_OK);
EXPECT_EQ(observed, MX_SIGNAL_LAST_HANDLE);
mx::event dup;
EXPECT_EQ(event.duplicate(MX_RIGHT_SAME_RIGHTS, &dup), MX_OK);
EXPECT_EQ(event.wait_one(MX_SIGNAL_LAST_HANDLE, 0u, &observed), MX_ERR_TIMED_OUT);
EXPECT_EQ(observed, 0u);
dup.reset();
EXPECT_EQ(
event.wait_one(MX_SIGNAL_LAST_HANDLE, MX_TIME_INFINITE, &observed), MX_OK);
EXPECT_EQ(observed, MX_SIGNAL_LAST_HANDLE);
EXPECT_EQ(event.signal(MX_SIGNAL_LAST_HANDLE, 0), MX_ERR_INVALID_ARGS);
END_TEST;
}
static bool replace_test() {
// Test that:
// 1- replacing the handle keeps the MX_SIGNAL_LAST_HANDLE signal.
// 2- replacing a duplicate does not spuriosly signal MX_SIGNAL_LAST_HANDLE.
// 3- closing the replacement does signal MX_SIGNAL_LAST_HANDLE.
// Note: we rely on a port to detect the edge transition, if any.
BEGIN_TEST;
mx::event old_ev;
ASSERT_EQ(mx::event::create(0u, &old_ev), MX_OK);
mx::event new_ev;
EXPECT_EQ(old_ev.replace(MX_RIGHT_SAME_RIGHTS, &new_ev), MX_OK);
mx_signals_t observed = 0u;
EXPECT_EQ(
new_ev.wait_one(MX_SIGNAL_LAST_HANDLE, MX_TIME_INFINITE, &observed), MX_OK);
EXPECT_EQ(observed, MX_SIGNAL_LAST_HANDLE);
mx::event dup;
EXPECT_EQ(new_ev.duplicate(MX_RIGHT_SAME_RIGHTS, &dup), MX_OK);
mx::port port;
ASSERT_EQ(mx::port::create(0, &port), MX_OK);
EXPECT_EQ(new_ev.wait_async(
port, 1u, MX_SIGNAL_LAST_HANDLE, MX_WAIT_ASYNC_ONCE), MX_OK);
mx_port_packet_t packet = {};
EXPECT_EQ(port.wait(0ull, &packet, 0u), MX_ERR_TIMED_OUT);
mx::event new_dup;
EXPECT_EQ(dup.replace(MX_RIGHT_SAME_RIGHTS, &new_dup), MX_OK);
EXPECT_EQ(port.wait(0ull, &packet, 0u), MX_ERR_TIMED_OUT);
new_dup.reset();
EXPECT_EQ(port.wait(MX_TIME_INFINITE, &packet, 0u), MX_OK);
EXPECT_EQ(packet.type, MX_PKT_TYPE_SIGNAL_ONE);
EXPECT_EQ(packet.signal.observed, MX_SIGNAL_LAST_HANDLE);
END_TEST;
}
static bool channel_test() {
// Test that:
// 1- Sending/receiving a duplicated object never triggers MX_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
// MX_SIGNAL_LAST_HANDLE.
// 3- Closing the receive side of #2 does trigger MX_SIGNAL_LAST_HANDLE.
BEGIN_TEST;
mx::event event;
ASSERT_EQ(mx::event::create(0u, &event), MX_OK);
mx::channel channel[2];
ASSERT_EQ(mx::channel::create(0u, &channel[0], &channel[1]), MX_OK);
mx::port port;
ASSERT_EQ(mx::port::create(0, &port), MX_OK);
mx_handle_t dup_ev;
EXPECT_EQ(mx_handle_duplicate(event.get(), MX_RIGHT_SAME_RIGHTS, &dup_ev), MX_OK);
ASSERT_EQ(event.wait_async(
port, 1u, MX_SIGNAL_LAST_HANDLE, MX_WAIT_ASYNC_ONCE), MX_OK);
uint32_t actual_b;
uint32_t actual_h;
mx_port_packet_t packet = {};
for (int ix = 0; ix != 4; ++ix) {
ASSERT_EQ(channel[0].write(0u, nullptr, 0u, &dup_ev, 1u), MX_OK);
dup_ev = 0u;
EXPECT_EQ(port.wait(0ull, &packet, 0u), MX_ERR_TIMED_OUT);
ASSERT_EQ(channel[1].read(
0u, nullptr, 0, &actual_b, &dup_ev, 1u, &actual_h), MX_OK);
EXPECT_EQ(port.wait(0ull, &packet, 0u), MX_ERR_TIMED_OUT);
}
ASSERT_EQ(channel[0].write(0u, nullptr, 0u, &dup_ev, 1u), MX_OK);
channel[0].reset();
EXPECT_EQ(port.wait(0ull, &packet, 0u), MX_ERR_TIMED_OUT);
channel[1].reset();
EXPECT_EQ(port.wait(MX_TIME_INFINITE, &packet, 0u), MX_OK);
EXPECT_EQ(packet.type, MX_PKT_TYPE_SIGNAL_ONE);
EXPECT_EQ(packet.signal.observed, MX_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;
}