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");