// Copyright 2013 The Chromium 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 "mojo/edk/system/core.h" #include <stdint.h> #include <limits> #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "mojo/edk/system/core_test_base.h" namespace mojo { namespace system { namespace { const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u}; const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u}; typedef test::CoreTestBase CoreTest; TEST_F(CoreTest, GetTimeTicksNow) { const MojoTimeTicks start = core()->GetTimeTicksNow(); EXPECT_NE(static_cast<MojoTimeTicks>(0), start) << "GetTimeTicksNow should return nonzero value"; base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(15)); const MojoTimeTicks finish = core()->GetTimeTicksNow(); // Allow for some fuzz in sleep. EXPECT_GE((finish - start), static_cast<MojoTimeTicks>(8000)) << "Sleeping should result in increasing time ticks"; } TEST_F(CoreTest, Basic) { MockHandleInfo info; EXPECT_EQ(0u, info.GetCtorCallCount()); MojoHandle h = CreateMockHandle(&info); EXPECT_EQ(1u, info.GetCtorCallCount()); EXPECT_NE(h, MOJO_HANDLE_INVALID); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); EXPECT_EQ(0u, info.GetReadMessageCallCount()); uint32_t num_bytes = 0; EXPECT_EQ( MOJO_RESULT_OK, core()->ReadMessage(h, NullUserPointer(), MakeUserPointer(&num_bytes), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetReadMessageCallCount()); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h, NullUserPointer(), NullUserPointer(), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(2u, info.GetReadMessageCallCount()); EXPECT_EQ(0u, info.GetWriteDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->WriteData(h, NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteDataCallCount()); EXPECT_EQ(0u, info.GetBeginWriteDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->BeginWriteData(h, NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetBeginWriteDataCallCount()); EXPECT_EQ(0u, info.GetEndWriteDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0)); EXPECT_EQ(1u, info.GetEndWriteDataCallCount()); EXPECT_EQ(0u, info.GetReadDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->ReadData(h, NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetReadDataCallCount()); EXPECT_EQ(0u, info.GetBeginReadDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->BeginReadData(h, NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ(1u, info.GetBeginReadDataCallCount()); EXPECT_EQ(0u, info.GetEndReadDataCallCount()); EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0)); EXPECT_EQ(1u, info.GetEndReadDataCallCount()); EXPECT_EQ(0u, info.GetAddWaiterCallCount()); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, NullUserPointer())); EXPECT_EQ(1u, info.GetAddWaiterCallCount()); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 0, NullUserPointer())); EXPECT_EQ(2u, info.GetAddWaiterCallCount()); MojoHandleSignalsState hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&hss))); EXPECT_EQ(3u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 10 * 1000, NullUserPointer())); EXPECT_EQ(4u, info.GetAddWaiterCallCount()); hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 10 * 1000, MakeUserPointer(&hss))); EXPECT_EQ(5u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany(MakeUserPointer(&h), MakeUserPointer(&handle_signals), 1, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); EXPECT_EQ(6u, info.GetAddWaiterCallCount()); uint32_t result_index = static_cast<uint32_t>(-1); EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany(MakeUserPointer(&h), MakeUserPointer(&handle_signals), 1, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), NullUserPointer())); EXPECT_EQ(7u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, result_index); hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany(MakeUserPointer(&h), MakeUserPointer(&handle_signals), 1, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), MakeUserPointer(&hss))); EXPECT_EQ(8u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); result_index = static_cast<uint32_t>(-1); hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany(MakeUserPointer(&h), MakeUserPointer(&handle_signals), 1, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(&hss))); EXPECT_EQ(9u, info.GetAddWaiterCallCount()); EXPECT_EQ(0u, result_index); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); EXPECT_EQ(0u, info.GetDtorCallCount()); EXPECT_EQ(0u, info.GetCloseCallCount()); EXPECT_EQ(0u, info.GetCancelAllWaitersCallCount()); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); EXPECT_EQ(1u, info.GetCancelAllWaitersCallCount()); EXPECT_EQ(1u, info.GetCloseCallCount()); EXPECT_EQ(1u, info.GetDtorCallCount()); // No waiters should ever have ever been added. EXPECT_EQ(0u, info.GetRemoveWaiterCallCount()); } TEST_F(CoreTest, InvalidArguments) { // |Close()|: { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(MOJO_HANDLE_INVALID)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(10)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(1000000000)); // Test a double-close. MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); EXPECT_EQ(1u, info.GetCloseCallCount()); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h)); EXPECT_EQ(1u, info.GetCloseCallCount()); } // |Wait()|: { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Wait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, NullUserPointer())); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Wait(10, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, NullUserPointer())); MojoHandleSignalsState hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Wait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&hss))); // On invalid argument, it shouldn't modify the handle signals state. EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals, hss.satisfied_signals); EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals, hss.satisfiable_signals); hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Wait(10, ~MOJO_HANDLE_SIGNAL_NONE, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&hss))); // On invalid argument, it shouldn't modify the handle signals state. EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals, hss.satisfied_signals); EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals, hss.satisfiable_signals); } // |WaitMany()|: { MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID}; MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE, ~MOJO_HANDLE_SIGNAL_NONE}; EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals), 0, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 0, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); // If |num_handles| is invalid, it should leave |result_index| and // |signals_states| alone. // (We use -1 internally; make sure that doesn't leak.) uint32_t result_index = 123; MojoHandleSignalsState hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 0, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(&hss))); EXPECT_EQ(123u, result_index); EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals, hss.satisfied_signals); EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 0, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals), 1, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); // But if a handle is bad, then it should set |result_index| but still leave // |signals_states| alone. result_index = static_cast<uint32_t>(-1); hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany( MakeUserPointer(handles), MakeUserPointer(signals), 1, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(&hss))); EXPECT_EQ(0u, result_index); EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals, hss.satisfied_signals); EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals, hss.satisfiable_signals); MockHandleInfo info[2]; handles[0] = CreateMockHandle(&info[0]); result_index = static_cast<uint32_t>(-1); hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany( MakeUserPointer(handles), MakeUserPointer(signals), 1, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(&hss))); EXPECT_EQ(0u, result_index); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); // On invalid argument, it'll leave |signals_states| alone. result_index = static_cast<uint32_t>(-1); hss = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany( MakeUserPointer(handles), MakeUserPointer(signals), 2, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(&hss))); EXPECT_EQ(1u, result_index); EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals, hss.satisfied_signals); EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals, hss.satisfiable_signals); handles[1] = handles[0] + 1; // Invalid handle. EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals), 2, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); handles[1] = CreateMockHandle(&info[1]); EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals), 2, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer())); // TODO(vtl): Test one where we get "failed precondition" only for the // second handle (and the first one is valid to wait on). EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1])); } // |CreateMessagePipe()|: Nothing to check (apart from things that cause // death). // |WriteMessage()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WriteMessage(MOJO_HANDLE_INVALID, NullUserPointer(), 0, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID}; // Huge handle count (implausibly big on some systems -- more than can be // stored in a 32-bit address space). // Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or // |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or // not. EXPECT_NE( MOJO_RESULT_OK, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), std::numeric_limits<uint32_t>::max(), MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Huge handle count (plausibly big). EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, core()->WriteMessage( h, NullUserPointer(), 0, MakeUserPointer(handles), std::numeric_limits<uint32_t>::max() / sizeof(handles[0]), MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Invalid handle in |handles|. EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Two invalid handles in |handles|. EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); // Can't send a handle over itself. handles[0] = h; EXPECT_EQ( MOJO_RESULT_BUSY, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(0u, info.GetWriteMessageCallCount()); MockHandleInfo info2; MojoHandle h2 = CreateMockHandle(&info2); // This is "okay", but |MockDispatcher| doesn't implement it. handles[0] = h2; EXPECT_EQ( MOJO_RESULT_UNIMPLEMENTED, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // One of the |handles| is still invalid. EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // One of the |handles| is the same as |handle|. handles[1] = h; EXPECT_EQ( MOJO_RESULT_BUSY, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // Can't send a handle twice in the same message. handles[1] = h2; EXPECT_EQ( MOJO_RESULT_BUSY, core()->WriteMessage(h, NullUserPointer(), 0, MakeUserPointer(handles), 2, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, info.GetWriteMessageCallCount()); // Note: Since we never successfully sent anything with it, |h2| should // still be valid. EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h2)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); } // |ReadMessage()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->ReadMessage(MOJO_HANDLE_INVALID, NullUserPointer(), NullUserPointer(), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); // Okay. uint32_t handle_count = 0; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h, NullUserPointer(), NullUserPointer(), NullUserPointer(), MakeUserPointer(&handle_count), MOJO_READ_MESSAGE_FLAG_NONE)); // Checked by |Core|, shouldn't go through to the dispatcher. EXPECT_EQ(1u, info.GetReadMessageCallCount()); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); } } // These test invalid arguments that should cause death if we're being paranoid // about checking arguments (which we would want to do if, e.g., we were in a // true "kernel" situation, but we might not want to do otherwise for // performance reasons). Probably blatant errors like passing in null pointers // (for required pointer arguments) will still cause death, but perhaps not // predictably. TEST_F(CoreTest, InvalidArgumentsDeath) { const char kMemoryCheckFailedRegex[] = "Check failed"; // |WaitMany()|: { MojoHandle handle = MOJO_HANDLE_INVALID; MojoHandleSignals signals = ~MOJO_HANDLE_SIGNAL_NONE; EXPECT_DEATH_IF_SUPPORTED( core()->WaitMany(NullUserPointer(), MakeUserPointer(&signals), 1, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer()), kMemoryCheckFailedRegex); EXPECT_DEATH_IF_SUPPORTED( core()->WaitMany(MakeUserPointer(&handle), NullUserPointer(), 1, MOJO_DEADLINE_INDEFINITE, NullUserPointer(), NullUserPointer()), kMemoryCheckFailedRegex); // TODO(vtl): |result_index| and |signals_states| are optional. Test them // with non-null invalid pointers? } // |CreateMessagePipe()|: { MojoHandle h; EXPECT_DEATH_IF_SUPPORTED( core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(), NullUserPointer()), kMemoryCheckFailedRegex); EXPECT_DEATH_IF_SUPPORTED( core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h), NullUserPointer()), kMemoryCheckFailedRegex); EXPECT_DEATH_IF_SUPPORTED( core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(), MakeUserPointer(&h)), kMemoryCheckFailedRegex); } // |WriteMessage()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); // Null |handles| with nonzero |num_handles|. EXPECT_DEATH_IF_SUPPORTED( core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), 1, MOJO_WRITE_MESSAGE_FLAG_NONE), kMemoryCheckFailedRegex); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); } // |ReadMessage()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); uint32_t handle_count = 1; EXPECT_DEATH_IF_SUPPORTED( core()->ReadMessage(h, NullUserPointer(), NullUserPointer(), NullUserPointer(), MakeUserPointer(&handle_count), MOJO_READ_MESSAGE_FLAG_NONE), kMemoryCheckFailedRegex); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h)); } } // TODO(vtl): test |Wait()| and |WaitMany()| properly // - including |WaitMany()| with the same handle more than once (with // same/different signals) TEST_F(CoreTest, MessagePipe) { MojoHandle h[2]; MojoHandleSignalsState hss[2]; uint32_t result_index; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h[0]), MakeUserPointer(&h[1]))); // Should get two distinct, valid handles. EXPECT_NE(h[0], MOJO_HANDLE_INVALID); EXPECT_NE(h[1], MOJO_HANDLE_INVALID); EXPECT_NE(h[0], h[1]); // Neither should be readable. MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE, MOJO_HANDLE_SIGNAL_READABLE}; result_index = static_cast<uint32_t>(-1); hss[0] = kEmptyMojoHandleSignalsState; hss[1] = kEmptyMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_DEADLINE_EXCEEDED, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, 0, MakeUserPointer(&result_index), MakeUserPointer(hss))); EXPECT_EQ(static_cast<uint32_t>(-1), result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfiable_signals); // Try to read anyway. char buffer[1] = {'a'}; uint32_t buffer_size = 1; EXPECT_EQ( MOJO_RESULT_SHOULD_WAIT, core()->ReadMessage(h[0], UserPointer<void>(buffer), MakeUserPointer(&buffer_size), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); // Check that it left its inputs alone. EXPECT_EQ('a', buffer[0]); EXPECT_EQ(1u, buffer_size); // Both should be writable. hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[0], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); // Also check that |h[1]| is writable using |WaitMany()|. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE; result_index = static_cast<uint32_t>(-1); hss[0] = kEmptyMojoHandleSignalsState; hss[1] = kEmptyMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_OK, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(hss))); EXPECT_EQ(1u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfiable_signals); // Write to |h[1]|. buffer[0] = 'b'; EXPECT_EQ( MOJO_RESULT_OK, core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Check that |h[0]| is now readable. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; signals[1] = MOJO_HANDLE_SIGNAL_READABLE; result_index = static_cast<uint32_t>(-1); hss[0] = kEmptyMojoHandleSignalsState; hss[1] = kEmptyMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_OK, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2, MOJO_DEADLINE_INDEFINITE, MakeUserPointer(&result_index), MakeUserPointer(hss))); EXPECT_EQ(0u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfiable_signals); // Read from |h[0]|. // First, get only the size. buffer_size = 0; EXPECT_EQ( MOJO_RESULT_RESOURCE_EXHAUSTED, core()->ReadMessage(h[0], NullUserPointer(), MakeUserPointer(&buffer_size), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(1u, buffer_size); // Then actually read it. buffer[0] = 'c'; buffer_size = 1; EXPECT_EQ( MOJO_RESULT_OK, core()->ReadMessage(h[0], UserPointer<void>(buffer), MakeUserPointer(&buffer_size), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ('b', buffer[0]); EXPECT_EQ(1u, buffer_size); // |h[0]| should no longer be readable. hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(h[0], MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfiable_signals); // Write to |h[0]|. buffer[0] = 'd'; EXPECT_EQ( MOJO_RESULT_OK, core()->WriteMessage(h[0], UserPointer<const void>(buffer), 1, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Close |h[0]|. EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[0])); // Check that |h[1]| is no longer writable (and will never be). hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); // Check that |h[1]| is still readable (for the moment). hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); // Discard a message from |h[1]|. EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, core()->ReadMessage(h[1], NullUserPointer(), NullUserPointer(), NullUserPointer(), NullUserPointer(), MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)); // |h[1]| is no longer readable (and will never be). hss[0] = kFullMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(0u, hss[0].satisfied_signals); EXPECT_EQ(0u, hss[0].satisfiable_signals); // Try writing to |h[1]|. buffer[0] = 'e'; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1])); } // Tests passing a message pipe handle. TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { const char kHello[] = "hello"; const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello)); const char kWorld[] = "world!!!"; const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld)); char buffer[100]; const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); uint32_t num_bytes; MojoHandle handles[10]; uint32_t num_handles; MojoHandleSignalsState hss; MojoHandle h_received; MojoHandle h_passing[2]; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h_passing[0]), MakeUserPointer(&h_passing[1]))); // Make sure that |h_passing[]| work properly. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); EXPECT_EQ(0u, num_handles); // Make sure that you can't pass either of the message pipe's handles over // itself. EXPECT_EQ(MOJO_RESULT_BUSY, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&h_passing[0]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&h_passing[1]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); MojoHandle h_passed[2]; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h_passed[0]), MakeUserPointer(&h_passed[1]))); // Make sure that |h_passed[]| work properly. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello), kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passed[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passed[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); EXPECT_EQ(0u, num_handles); // Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), kWorldSize, MakeUserPointer(&h_passed[1]), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); EXPECT_EQ(1u, num_handles); h_received = handles[0]; EXPECT_NE(h_received, MOJO_HANDLE_INVALID); EXPECT_NE(h_received, h_passing[0]); EXPECT_NE(h_received, h_passing[1]); EXPECT_NE(h_received, h_passed[0]); // Note: We rely on the Mojo system not re-using handle values very often. EXPECT_NE(h_received, h_passed[1]); // |h_passed[1]| should no longer be valid; check that trying to close it // fails. See above note. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h_passed[1])); // Write to |h_passed[0]|. Should receive on |h_received|. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello), kHelloSize, NullUserPointer(), 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_received, UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); EXPECT_EQ(0u, num_handles); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passed[0])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_received)); } TEST_F(CoreTest, DataPipe) { MojoHandle ph, ch; // p is for producer and c is for consumer. MojoHandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph), MakeUserPointer(&ch))); // Should get two distinct, valid handles. EXPECT_NE(ph, MOJO_HANDLE_INVALID); EXPECT_NE(ch, MOJO_HANDLE_INVALID); EXPECT_NE(ph, ch); // Producer should be never-readable, but already writable. hss = kEmptyMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ph, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ph, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); // Consumer should be never-writable, and not yet readable. hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); // Write. char elements[2] = {'A', 'B'}; uint32_t num_bytes = 2u; EXPECT_EQ(MOJO_RESULT_OK, core()->WriteData(ph, UserPointer<const void>(elements), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(2u, num_bytes); // Consumer should now be readable. hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); // Peek one character. elements[0] = -1; elements[1] = -1; num_bytes = 1u; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData( ch, UserPointer<void>(elements), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_PEEK)); EXPECT_EQ('A', elements[0]); EXPECT_EQ(-1, elements[1]); // Read one character. elements[0] = -1; elements[1] = -1; num_bytes = 1u; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, UserPointer<void>(elements), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ('A', elements[0]); EXPECT_EQ(-1, elements[1]); // Two-phase write. void* write_ptr = nullptr; num_bytes = 0u; ASSERT_EQ(MOJO_RESULT_OK, core()->BeginWriteData(ph, MakeUserPointer(&write_ptr), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); // We count on the default options providing a decent buffer size. ASSERT_GE(num_bytes, 3u); // Trying to do a normal write during a two-phase write should fail. elements[0] = 'X'; num_bytes = 1u; EXPECT_EQ(MOJO_RESULT_BUSY, core()->WriteData(ph, UserPointer<const void>(elements), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); // Actually write the data, and complete it now. static_cast<char*>(write_ptr)[0] = 'C'; static_cast<char*>(write_ptr)[1] = 'D'; static_cast<char*>(write_ptr)[2] = 'E'; EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u)); // Query how much data we have. num_bytes = 0; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_QUERY)); EXPECT_EQ(4u, num_bytes); // Try to query with peek. Should fail. num_bytes = 0; EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK)); EXPECT_EQ(0u, num_bytes); // Try to discard ten characters, in all-or-none mode. Should fail. num_bytes = 10; EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, core()->ReadData( ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); // Try to discard two characters, in peek mode. Should fail. num_bytes = 2; EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_PEEK)); // Discard two characters. num_bytes = 2; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData( ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); // Try a two-phase read of the remaining two bytes with peek. Should fail. const void* read_ptr = nullptr; num_bytes = 2; ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->BeginReadData(ch, MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_PEEK)); // Read the remaining two characters, in two-phase mode (all-or-none). num_bytes = 2; ASSERT_EQ(MOJO_RESULT_OK, core()->BeginReadData(ch, MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_ALL_OR_NONE)); // Note: Count on still being able to do the contiguous read here. ASSERT_EQ(2u, num_bytes); // Discarding right now should fail. num_bytes = 1; EXPECT_EQ(MOJO_RESULT_BUSY, core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_DISCARD)); // Actually check our data and end the two-phase read. EXPECT_EQ('D', static_cast<const char*>(read_ptr)[0]); EXPECT_EQ('E', static_cast<const char*>(read_ptr)[1]); EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 2u)); // Consumer should now be no longer readable. hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); // TODO(vtl): More. // Close the producer. EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph)); // The consumer should now be never-readable. hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch)); } // Tests passing data pipe producer and consumer handles. TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { const char kHello[] = "hello"; const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello)); const char kWorld[] = "world!!!"; const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld)); char buffer[100]; const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer)); uint32_t num_bytes; MojoHandle handles[10]; uint32_t num_handles; MojoHandleSignalsState hss; MojoHandle h_passing[2]; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h_passing[0]), MakeUserPointer(&h_passing[1]))); MojoHandle ph, ch; EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph), MakeUserPointer(&ch))); // Send |ch| from |h_passing[0]| to |h_passing[1]|. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); EXPECT_EQ(1u, num_handles); MojoHandle ch_received = handles[0]; EXPECT_NE(ch_received, MOJO_HANDLE_INVALID); EXPECT_NE(ch_received, h_passing[0]); EXPECT_NE(ch_received, h_passing[1]); EXPECT_NE(ch_received, ph); // Note: We rely on the Mojo system not re-using handle values very often. EXPECT_NE(ch_received, ch); // |ch| should no longer be valid; check that trying to close it fails. See // above note. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ch)); // Write to |ph|. Should receive on |ch_received|. num_bytes = kWorldSize; EXPECT_EQ(MOJO_RESULT_OK, core()->WriteData(ph, UserPointer<const void>(kWorld), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); // Now pass |ph| in the same direction. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), kWorldSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); EXPECT_EQ(1u, num_handles); MojoHandle ph_received = handles[0]; EXPECT_NE(ph_received, MOJO_HANDLE_INVALID); EXPECT_NE(ph_received, h_passing[0]); EXPECT_NE(ph_received, h_passing[1]); EXPECT_NE(ph_received, ch_received); // Again, rely on the Mojo system not re-using handle values very often. EXPECT_NE(ph_received, ph); // |ph| should no longer be valid; check that trying to close it fails. See // above note. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ph)); // Write to |ph_received|. Should receive on |ch_received|. num_bytes = kHelloSize; EXPECT_EQ(MOJO_RESULT_OK, core()->WriteData(ph_received, UserPointer<const void>(kHello), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); ph = ph_received; ph_received = MOJO_HANDLE_INVALID; ch = ch_received; ch_received = MOJO_HANDLE_INVALID; // Make sure that |ph| can't be sent if it's in a two-phase write. void* write_ptr = nullptr; num_bytes = 0; ASSERT_EQ(MOJO_RESULT_OK, core()->BeginWriteData(ph, MakeUserPointer(&write_ptr), MakeUserPointer(&num_bytes), MOJO_WRITE_DATA_FLAG_NONE)); ASSERT_GE(num_bytes, 1u); EXPECT_EQ(MOJO_RESULT_BUSY, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); // But |ch| can, even if |ph| is in a two-phase write. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); ch = MOJO_HANDLE_INVALID; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, NullUserPointer())); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kHelloSize, num_bytes); EXPECT_STREQ(kHello, buffer); EXPECT_EQ(1u, num_handles); ch = handles[0]; EXPECT_NE(ch, MOJO_HANDLE_INVALID); // Complete the two-phase write. static_cast<char*>(write_ptr)[0] = 'x'; EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 1)); // Wait for |ch| to be readable. hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); // Make sure that |ch| can't be sent if it's in a two-phase read. const void* read_ptr = nullptr; num_bytes = 1; ASSERT_EQ(MOJO_RESULT_OK, core()->BeginReadData(ch, MakeUserPointer(&read_ptr), MakeUserPointer(&num_bytes), MOJO_READ_DATA_FLAG_ALL_OR_NONE)); EXPECT_EQ(MOJO_RESULT_BUSY, core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello), kHelloSize, MakeUserPointer(&ch), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); // But |ph| can, even if |ch| is in a two-phase read. EXPECT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld), kWorldSize, MakeUserPointer(&ph), 1, MOJO_WRITE_MESSAGE_FLAG_NONE)); ph = MOJO_HANDLE_INVALID; hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, core()->ReadMessage( h_passing[1], UserPointer<void>(buffer), MakeUserPointer(&num_bytes), MakeUserPointer(handles), MakeUserPointer(&num_handles), MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(kWorldSize, num_bytes); EXPECT_STREQ(kWorld, buffer); EXPECT_EQ(1u, num_handles); ph = handles[0]; EXPECT_NE(ph, MOJO_HANDLE_INVALID); // Complete the two-phase read. EXPECT_EQ('x', static_cast<const char*>(read_ptr)[0]); EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 1)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1])); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph)); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch)); } // TODO(vtl): Test |DuplicateBufferHandle()| and |MapBuffer()|. } // namespace } // namespace system } // namespace mojo