Added MojoNewWait and MojoNewWaitMany, along with unit tests. R=viettrungluu@chromium.org BUG=365436 Review URL: https://codereview.chromium.org/774673003
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc index b138a2d..0393748 100644 --- a/mojo/edk/embedder/embedder_unittest.cc +++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -24,6 +24,13 @@ namespace embedder { namespace { +const MojoHandleSignals kSignalReadadableWritable = + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; + +const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + class ScopedTestChannel { public: // Creates a channel that lives on a given I/O thread (determined by the given @@ -123,8 +130,12 @@ 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Now wait for the other side to become readable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + MojoHandleSignalsState state; + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); char buffer[1000] = {}; uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); @@ -188,8 +199,12 @@ nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Wait for |client_mp| to become readable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + MojoHandleSignalsState state; + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Read a message from |client_mp|. char buffer[1000] = {}; @@ -206,8 +221,10 @@ h1 = handles[0]; // Wait for |h1| to become readable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(h1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Read a message from |h1|. memset(buffer, 0, sizeof(buffer)); @@ -222,8 +239,10 @@ EXPECT_EQ(0u, num_handles); // Wait for |h1| to become readable (again). - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(h1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Read the second message from |h1|. memset(buffer, 0, sizeof(buffer)); @@ -242,8 +261,10 @@ nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // Wait for |h0| to become readable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(h0, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Read a message from |h0|. memset(buffer, 0, sizeof(buffer)); @@ -282,6 +303,7 @@ // 10. (close) // 11. (wait/cl.) // 12. (wait/cl.) + #if defined(OS_ANDROID) // Android multi-process tests are not executing the new process. This is flaky. #define MAYBE_MultiprocessChannels DISABLED_MultiprocessChannels @@ -313,8 +335,13 @@ // |server_mp|), we die with a fatal error in |Channel::HandleLocalError()|. // 2. Read a message from |server_mp|. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(server_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + MojoHandleSignalsState state; + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(server_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); + char buffer[1000] = {}; uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -346,8 +373,11 @@ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(server_mp)); // 9. Read a message from |mp0|, which should have |mp2| attached. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp0, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(mp0, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); + memset(buffer, 0, sizeof(buffer)); num_bytes = static_cast<uint32_t>(sizeof(buffer)); MojoHandle mp2 = MOJO_HANDLE_INVALID; @@ -362,8 +392,13 @@ EXPECT_NE(mp2, MOJO_HANDLE_INVALID); // 7. Read a message from |mp2|. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfiable_signals); + memset(buffer, 0, sizeof(buffer)); num_bytes = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -380,8 +415,11 @@ // TODO(vtl): crbug.com/351768 #if 0 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + MojoNewWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, + &state)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfiable_signals); #endif EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp2)); } @@ -407,8 +445,13 @@ CHECK(client_channel.channel_info() != nullptr); // 1. Read the first message from |client_mp|. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + MojoHandleSignalsState state; + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); + char buffer[1000] = {}; uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -426,8 +469,15 @@ 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); // 4. Read a message from |client_mp|, which should have |mp1| attached. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + // The other end of the handle may or may not be closed at this point, so we + // can't test MOJO_HANDLE_SIGNAL_WRITABLE or MOJO_HANDLE_SIGNAL_PEER_CLOSED. + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, + state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, + state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); // TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd // die (again due to |Channel::HandleLocalError()|). memset(buffer, 0, sizeof(buffer)); @@ -470,8 +520,11 @@ mp2 = MOJO_HANDLE_INVALID; // 3. Read a message from |mp1|. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, - MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoNewWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(kSignalReadadableWritable, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); + memset(buffer, 0, sizeof(buffer)); num_bytes = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -482,9 +535,11 @@ EXPECT_STREQ(kFoo, buffer); // 11. Wait on |mp1| (which should eventually fail) and then close it. - EXPECT_EQ( - MOJO_RESULT_FAILED_PRECONDITION, - MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoNewWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp1)); }
diff --git a/mojo/edk/embedder/entrypoints.cc b/mojo/edk/embedder/entrypoints.cc index 7b2e53f..6ecdd14 100644 --- a/mojo/edk/embedder/entrypoints.cc +++ b/mojo/edk/embedder/entrypoints.cc
@@ -41,6 +41,25 @@ : result; } +MojoResult MojoNewWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + MojoHandleSignalsState* signals_state) { + return g_core->Wait(handle, signals, deadline, + MakeUserPointer(signals_state)); +} + +MojoResult MojoNewWaitMany(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline, + uint32_t* result_index, + MojoHandleSignalsState* signals_states) { + return g_core->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals), + num_handles, deadline, MakeUserPointer(result_index), + MakeUserPointer(signals_states)); +} + MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options, MojoHandle* message_pipe_handle0, MojoHandle* message_pipe_handle1) {
diff --git a/mojo/public/c/system/functions.h b/mojo/public/c/system/functions.h index 6045f2f..21a0db5 100644 --- a/mojo/public/c/system/functions.h +++ b/mojo/public/c/system/functions.h
@@ -26,7 +26,7 @@ // whether a given "in/out" parameter is used for input, output, or both.) // Platform-dependent monotonically increasing tick count representing "right -// now." The resolution of this clock is ~1-15ms. Resolution varies depending +// now." The resolution of this clock is ~1-15ms. Resolution varies depending // on hardware/operating system configuration. MOJO_SYSTEM_EXPORT MojoTimeTicks MojoGetTimeTicksNow(void); @@ -101,6 +101,90 @@ uint32_t num_handles, MojoDeadline deadline); +// Waits on the given handle until one of the following happens: +// - A signal indicated by |signals| is satisfied. +// - It becomes known that no signal indicated by |signals| will ever be +// satisfied. (See the description of the |MOJO_RESULT_CANCELLED| and +// |MOJO_RESULT_FAILED_PRECONDITION| return values below.) +// - Until |deadline| has passed. +// +// If |deadline| is |MOJO_DEADLINE_INDEFINITE|, this will wait "forever" (until +// one of the other wait termination conditions is satisfied). If |deadline| is +// 0, this will return |MOJO_RESULT_DEADLINE_EXCEEDED| only if one of the other +// termination conditions (e.g., a signal is satisfied, or all signals are +// unsatisfiable) is not already satisfied. +// +// |signals_state| (optional): See documentation for |MojoHandleSignalsState|. +// +// Returns: +// |MOJO_RESULT_OK| if some signal in |signals| was satisfied (or is already +// satisfied). +// |MOJO_RESULT_CANCELLED| if |handle| was closed (necessarily from another +// thread) during the wait. +// |MOJO_RESULT_INVALID_ARGUMENT| if |handle| is not a valid handle (e.g., if +// it has already been closed). The |signals_state| value is unchanged. +// |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of +// the signals being satisfied. +// |MOJO_RESULT_FAILED_PRECONDITION| if it becomes known that none of the +// signals in |signals| can ever be satisfied (e.g., when waiting on one +// end of a message pipe and the other end is closed). +// +// If there are multiple waiters (on different threads, obviously) waiting on +// the same handle and signal, and that signal becomes is satisfied, all waiters +// will be awoken. +MOJO_SYSTEM_EXPORT MojoResult +MojoNewWait(MojoHandle handle, + MojoHandleSignals signals, + MojoDeadline deadline, + struct MojoHandleSignalsState* signals_state); // Optional out. + +// Waits on |handles[0]|, ..., |handles[num_handles-1]| until: +// - (At least) one handle satisfies a signal indicated in its respective +// |signals[0]|, ..., |signals[num_handles-1]|. +// - It becomes known that no signal in some |signals[i]| will ever be +// satisfied. +// - |deadline| has passed. +// +// This means that |MojoWaitMany()| behaves as if |MojoWait()| were called on +// each handle/signals pair simultaneously, completing when the first +// |MojoWait()| would complete. +// +// See |MojoWait()| for more details about |deadline|. +// +// |result_index| (optional) is used to return the index of the handle that +// caused the call to return. For example, the index |i| (from 0 to +// |num_handles-1|) if |handle[i]| satisfies a signal from |signals[i]|. You +// must manually initialize this to a suitable sentinel value (e.g. -1) +// before you make this call because this value is not updated if there is +// no specific handle that causes the function to return. Pass null if you +// don't need this value to be returned. +// +// |signals_states| (optional) points to an array of size |num_handles| of +// MojoHandleSignalsState. See |MojoHandleSignalsState| for more details +// about the meaning of each array entry. This array is not an atomic +// snapshot. The array will be updated if the function does not return +// |MOJO_RESULT_INVALID_ARGUMENT| or |MOJO_RESULT_RESOURCE_EXHAUSTED|. +// +// Returns: +// |MOJO_RESULT_CANCELLED| if some |handle[i]| was closed (necessarily from +// another thread) during the wait. +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if there are too many handles. The +// |signals_state| array is unchanged. +// |MOJO_RESULT_INVALID_ARGUMENT| if some |handle[i]| is not a valid handle +// (e.g., if it is zero or if it has already been closed). The +// |signals_state| array is unchanged. +// |MOJO_RESULT_DEADLINE_EXCEEDED| if the deadline has passed without any of +// handles satisfying any of its signals. +// |MOJO_RESULT_FAILED_PRECONDITION| if it is or becomes impossible that SOME +// |handle[i]| will ever satisfy any of the signals in |signals[i]|. +MOJO_SYSTEM_EXPORT MojoResult +MojoNewWaitMany(const MojoHandle* handles, + const MojoHandleSignals* signals, + uint32_t num_handles, + MojoDeadline deadline, + uint32_t* result_index, // Optional out + struct MojoHandleSignalsState* signals_states); // Optional out + #ifdef __cplusplus } // extern "C" #endif
diff --git a/mojo/public/c/system/tests/core_unittest.cc b/mojo/public/c/system/tests/core_unittest.cc index d071f48..d8ae4b0 100644 --- a/mojo/public/c/system/tests/core_unittest.cc +++ b/mojo/public/c/system/tests/core_unittest.cc
@@ -13,6 +13,13 @@ namespace mojo { namespace { +const MojoHandleSignals kSignalReadadableWritable = + MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; + +const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + TEST(CoreTest, GetTimeTicksNow) { const MojoTimeTicks start = MojoGetTimeTicksNow(); EXPECT_NE(static_cast<MojoTimeTicks>(0), start) @@ -34,21 +41,23 @@ // Wait: EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, 1000000)); + MojoNewWait(MOJO_HANDLE_INVALID, ~MOJO_HANDLE_SIGNAL_NONE, 1000000, + NULL)); + h0 = MOJO_HANDLE_INVALID; sig = ~MOJO_HANDLE_SIGNAL_NONE; - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE)); + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + MojoNewWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE, NULL, NULL)); // Message pipe: EXPECT_EQ( MOJO_RESULT_INVALID_ARGUMENT, MojoWriteMessage(h0, buffer, 3, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); buffer_size = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ( - MOJO_RESULT_INVALID_ARGUMENT, - MojoReadMessage( - h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoReadMessage(h0, buffer, &buffer_size, NULL, NULL, + MOJO_READ_MESSAGE_FLAG_NONE)); // Data pipe: buffer_size = static_cast<uint32_t>(sizeof(buffer)); @@ -56,16 +65,16 @@ MojoWriteData(h0, buffer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE)); write_pointer = NULL; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoBeginWriteData( - h0, &write_pointer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE)); + MojoBeginWriteData(h0, &write_pointer, &buffer_size, + MOJO_WRITE_DATA_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoEndWriteData(h0, 1)); buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoReadData(h0, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); read_pointer = NULL; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoBeginReadData( - h0, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); + MojoBeginReadData(h0, &read_pointer, &buffer_size, + MOJO_READ_DATA_FLAG_NONE)); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoEndReadData(h0, 1)); // Shared buffer: @@ -88,45 +97,56 @@ EXPECT_NE(h0, MOJO_HANDLE_INVALID); EXPECT_NE(h1, MOJO_HANDLE_INVALID); - // Shouldn't be readable. + // Shouldn't be readable, we haven't written anything. + MojoHandleSignalsState state; EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 0)); + MojoNewWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 0, &state)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Should be writable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &state)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Try to read. buffer_size = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ( - MOJO_RESULT_SHOULD_WAIT, - MojoReadMessage( - h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, + MojoReadMessage(h0, buffer, &buffer_size, NULL, NULL, + MOJO_READ_MESSAGE_FLAG_NONE)); // Write to |h1|. static const char kHello[] = "hello"; buffer_size = static_cast<uint32_t>(sizeof(kHello)); - EXPECT_EQ( - MOJO_RESULT_OK, - MojoWriteMessage( - h1, kHello, buffer_size, NULL, 0, MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h1, kHello, buffer_size, NULL, 0, + MOJO_WRITE_MESSAGE_FLAG_NONE)); // |h0| should be readable. + uint32_t result_index = 1; + MojoHandleSignalsState states[1]; sig = MOJO_HANDLE_SIGNAL_READABLE; EXPECT_EQ(MOJO_RESULT_OK, - MojoWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE)); + MojoNewWaitMany(&h0, &sig, 1, MOJO_DEADLINE_INDEFINITE, + &result_index, states)); + + EXPECT_EQ(0u, result_index); + EXPECT_EQ(kSignalReadadableWritable, states[0].satisfied_signals); + EXPECT_EQ(kSignalAll, states[0].satisfiable_signals); // Read from |h0|. buffer_size = static_cast<uint32_t>(sizeof(buffer)); - EXPECT_EQ( - MOJO_RESULT_OK, - MojoReadMessage( - h0, buffer, &buffer_size, NULL, NULL, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(h0, buffer, &buffer_size, NULL, + NULL, MOJO_READ_MESSAGE_FLAG_NONE)); EXPECT_EQ(static_cast<uint32_t>(sizeof(kHello)), buffer_size); EXPECT_STREQ(kHello, buffer); // |h0| should no longer be readable. EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 10)); + MojoNewWait(h0, MOJO_HANDLE_SIGNAL_READABLE, 10, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); + EXPECT_EQ(kSignalAll, state.satisfiable_signals); // Close |h0|. EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0)); @@ -134,8 +154,11 @@ // |h1| should no longer be readable or writable. EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, - MojoWait( - h1, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, 1000)); + MojoNewWait(h1, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + 1000, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1)); } @@ -164,11 +187,21 @@ EXPECT_NE(hc, MOJO_HANDLE_INVALID); // The consumer |hc| shouldn't be readable. + MojoHandleSignalsState state; EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0)); + MojoNewWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfiable_signals); // The producer |hp| should be writable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(hp, MOJO_HANDLE_SIGNAL_WRITABLE, 0)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(hp, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfiable_signals); // Try to read from |hc|. buffer_size = static_cast<uint32_t>(sizeof(buffer)); @@ -178,26 +211,32 @@ // Try to begin a two-phase read from |hc|. read_pointer = NULL; EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, - MojoBeginReadData( - hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); + MojoBeginReadData(hc, &read_pointer, &buffer_size, + MOJO_READ_DATA_FLAG_NONE)); // Write to |hp|. static const char kHello[] = "hello "; // Don't include terminating null. buffer_size = static_cast<uint32_t>(strlen(kHello)); - EXPECT_EQ( - MOJO_RESULT_OK, - MojoWriteData(hp, kHello, &buffer_size, MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWriteData(hp, kHello, &buffer_size, + MOJO_WRITE_MESSAGE_FLAG_NONE)); // |hc| should be(come) readable. + uint32_t result_index = 1; + MojoHandleSignalsState states[1]; sig = MOJO_HANDLE_SIGNAL_READABLE; EXPECT_EQ(MOJO_RESULT_OK, - MojoWaitMany(&hc, &sig, 1, MOJO_DEADLINE_INDEFINITE)); + MojoNewWaitMany(&hc, &sig, 1, MOJO_DEADLINE_INDEFINITE, + &result_index, states)); + + EXPECT_EQ(0u, result_index); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, states[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + states[0].satisfiable_signals); // Do a two-phase write to |hp|. - EXPECT_EQ(MOJO_RESULT_OK, - MojoBeginWriteData( - hp, &write_pointer, &buffer_size, MOJO_WRITE_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoBeginWriteData(hp, &write_pointer, &buffer_size, + MOJO_WRITE_DATA_FLAG_NONE)); static const char kWorld[] = "world"; ASSERT_GE(buffer_size, sizeof(kWorld)); // Include the terminating null. @@ -215,13 +254,18 @@ EXPECT_EQ(MOJO_RESULT_OK, MojoClose(hp)); // |hc| should still be readable. - EXPECT_EQ(MOJO_RESULT_OK, MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoNewWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 0, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + state.satisfiable_signals); // Do a two-phase read from |hc|. read_pointer = NULL; - EXPECT_EQ(MOJO_RESULT_OK, - MojoBeginReadData( - hc, &read_pointer, &buffer_size, MOJO_READ_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoBeginReadData(hc, &read_pointer, &buffer_size, + MOJO_READ_DATA_FLAG_NONE)); ASSERT_LE(buffer_size, sizeof(buffer) - 1); memcpy(&buffer[1], read_pointer, buffer_size); EXPECT_EQ(MOJO_RESULT_OK, MojoEndReadData(hc, buffer_size)); @@ -229,7 +273,10 @@ // |hc| should no longer be readable. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - MojoWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 1000)); + MojoNewWait(hc, MOJO_HANDLE_SIGNAL_READABLE, 1000, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(hc));
diff --git a/mojo/public/c/system/tests/core_unittest_pure_c.c b/mojo/public/c/system/tests/core_unittest_pure_c.c index 33de688..4696934 100644 --- a/mojo/public/c/system/tests/core_unittest_pure_c.c +++ b/mojo/public/c/system/tests/core_unittest_pure_c.c
@@ -61,8 +61,15 @@ EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(NULL, &handle0, &handle1)); signals = MOJO_HANDLE_SIGNAL_READABLE; + uint32_t result_index = 1; + struct MojoHandleSignalsState states[1]; EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - MojoWaitMany(&handle0, &signals, 1, 1)); + MojoNewWaitMany(&handle0, &signals, 1, 1, &result_index, states)); + + EXPECT_EQ(0u, result_index); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, states[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + states[0].satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(handle0, @@ -72,9 +79,16 @@ 0u, MOJO_WRITE_DATA_FLAG_NONE)); + struct MojoHandleSignalsState state; EXPECT_EQ( MOJO_RESULT_OK, - MojoWait(handle1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE)); + MojoNewWait(handle1, MOJO_HANDLE_SIGNAL_READABLE, + MOJO_DEADLINE_INDEFINITE, &state)); + + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + state.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + state.satisfiable_signals); num_bytes = (uint32_t)sizeof(buffer); EXPECT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h index 9b1eedc..a88b024 100644 --- a/mojo/public/c/system/types.h +++ b/mojo/public/c/system/types.h
@@ -165,7 +165,14 @@ #define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((MojoHandleSignals)1 << 2) #endif -// TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany. +// |MojoHandleSignalsState|: Returned by wait functions to indicate the +// signaling state of handles. Members are as follows: +// - |satisfied signals|: Bitmask of signals that were satisfied at some time +// before the call returned. +// - |satisfiable signals|: These are the signals that are possible to +// satisfy. For example, if the return value was +// |MOJO_RESULT_FAILED_PRECONDITION|, you can use this field to +// determine which, if any, of the signals can still be satisfied. // Note: This struct is not extensible (and only has 32-bit quantities), so it's // 32-bit-aligned. MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int32_t) == 4, "int32_t has weird alignment");