Adding MOJO_HANDLE_SIGNAL_PEER_CLOSED to be notified when a peer is closed.

BUG=436227
R=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/741503003
diff --git a/mojo/edk/js/core.cc b/mojo/edk/js/core.cc
index 232f0e3..e70931d 100644
--- a/mojo/edk/js/core.cc
+++ b/mojo/edk/js/core.cc
@@ -288,6 +288,8 @@
             .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE)
             .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
             .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE)
+            .SetValue("HANDLE_SIGNAL_PEER_CLOSED",
+                      MOJO_HANDLE_SIGNAL_PEER_CLOSED)
 
             .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
                       MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
diff --git a/mojo/edk/system/channel_unittest.cc b/mojo/edk/system/channel_unittest.cc
index 68b1315..e84ab5b 100644
--- a/mojo/edk/system/channel_unittest.cc
+++ b/mojo/edk/system/channel_unittest.cc
@@ -243,8 +243,8 @@
             waiter.Wait(MOJO_DEADLINE_INDEFINITE, nullptr));
   HandleSignalsState hss;
   mp->RemoveWaiter(0, &waiter, &hss);
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   mp->Close(0);
 
@@ -279,8 +279,8 @@
   HandleSignalsState hss;
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
             mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, &hss));
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   mp->Close(0);
 
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
index 3969322..51a4022 100644
--- a/mojo/edk/system/core_unittest.cc
+++ b/mojo/edk/system/core_unittest.cc
@@ -18,6 +18,9 @@
 
 const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u};
 const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u};
+const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
+                                      MOJO_HANDLE_SIGNAL_WRITABLE |
+                                      MOJO_HANDLE_SIGNAL_PEER_CLOSED;
 
 typedef test::CoreTestBase CoreTest;
 
@@ -545,11 +548,9 @@
                        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(kAllSignals, 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);
+  EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals);
 
   // Try to read anyway.
   char buffer[1] = {'a'};
@@ -568,14 +569,12 @@
   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);
+  EXPECT_EQ(kAllSignals, 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);
+  EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals);
 
   // Also check that |h[1]| is writable using |WaitMany()|.
   signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
@@ -590,11 +589,9 @@
                        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(kAllSignals, 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);
+  EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals);
 
   // Write to |h[1]|.
   buffer[0] = 'b';
@@ -617,11 +614,9 @@
   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(kAllSignals, 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);
+  EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals);
 
   // Read from |h[0]|.
   // First, get only the size.
@@ -649,8 +644,7 @@
             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);
+  EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals);
 
   // Write to |h[0]|.
   buffer[0] = 'd';
@@ -667,15 +661,19 @@
   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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss[0].satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss[0].satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss[0].satisfiable_signals);
 
   // Discard a message from |h[1]|.
   EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
@@ -688,8 +686,8 @@
   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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfiable_signals);
 
   // Try writing to |h[1]|.
   buffer[0] = 'e';
@@ -732,8 +730,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -773,8 +770,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -797,8 +793,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -833,8 +828,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -870,12 +864,14 @@
       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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Consumer should be never-writable, and not yet readable.
   hss = kFullMojoHandleSignalsState;
@@ -883,13 +879,15 @@
       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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Write.
   signed char elements[2] = {'A', 'B'};
@@ -905,7 +903,8 @@
   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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Peek one character.
   elements[0] = -1;
@@ -1022,7 +1021,8 @@
       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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // TODO(vtl): More.
 
@@ -1034,8 +1034,8 @@
   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_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch));
 }
@@ -1075,8 +1075,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -1111,7 +1110,8 @@
             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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
   num_bytes = kBufferSize;
   EXPECT_EQ(MOJO_RESULT_OK,
             core()->ReadData(ch_received, UserPointer<void>(buffer),
@@ -1131,8 +1131,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -1167,7 +1166,8 @@
             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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
   num_bytes = kBufferSize;
   EXPECT_EQ(MOJO_RESULT_OK,
             core()->ReadData(ch_received, UserPointer<void>(buffer),
@@ -1225,7 +1225,8 @@
   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);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Make sure that |ch| can't be sent if it's in a two-phase read.
   const void* read_ptr = nullptr;
@@ -1251,8 +1252,7 @@
                          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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   num_bytes = kBufferSize;
   num_handles = arraysize(handles);
   EXPECT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/edk/system/local_data_pipe.cc b/mojo/edk/system/local_data_pipe.cc
index 177b238..8b9f673 100644
--- a/mojo/edk/system/local_data_pipe.cc
+++ b/mojo/edk/system/local_data_pipe.cc
@@ -160,7 +160,10 @@
         !producer_in_two_phase_write_no_lock())
       rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
     rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
+  } else {
+    rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   }
+  rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   return rv;
 }
 
@@ -293,6 +296,9 @@
   } else if (producer_open_no_lock()) {
     rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
   }
+  if (!producer_open_no_lock())
+    rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+  rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   return rv;
 }
 
diff --git a/mojo/edk/system/local_data_pipe_unittest.cc b/mojo/edk/system/local_data_pipe_unittest.cc
index 9ba6b21..cea50a0 100644
--- a/mojo/edk/system/local_data_pipe_unittest.cc
+++ b/mojo/edk/system/local_data_pipe_unittest.cc
@@ -239,7 +239,8 @@
       MOJO_RESULT_FAILED_PRECONDITION,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Already writable.
   waiter.Init();
@@ -266,7 +267,8 @@
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Peek one element.
   elements[0] = -1;
@@ -289,7 +291,8 @@
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Do it again.
   waiter.Init();
@@ -314,7 +317,8 @@
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Try writing, using a two-phase write.
   void* buffer = nullptr;
@@ -357,7 +361,8 @@
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Write one element.
   elements[0] = 123;
@@ -381,12 +386,75 @@
   EXPECT_EQ(12u, context);
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   dp->ProducerClose();
 }
 
+TEST(LocalDataPipeTest, PeerClosedWaiting) {
+  const MojoCreateDataPipeOptions options = {
+      kSizeOfOptions,                           // |struct_size|.
+      MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,  // |flags|.
+      static_cast<uint32_t>(sizeof(int32_t)),   // |element_num_bytes|.
+      2 * sizeof(int32_t)                       // |capacity_num_bytes|.
+  };
+  MojoCreateDataPipeOptions validated_options = {0};
+  EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions(
+                                MakeUserPointer(&options), &validated_options));
+
+  Waiter waiter;
+  HandleSignalsState hss;
+
+  // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on producer.
+  {
+    scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
+    // Add a waiter.
+    waiter.Init();
+    ASSERT_EQ(MOJO_RESULT_OK,
+              dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12,
+                                    nullptr));
+
+    // Close the consumer.
+    dp->ConsumerClose();
+
+    // It should be signaled.
+    uint32_t context = 0;
+    EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context));
+    EXPECT_EQ(12u, context);
+    hss = HandleSignalsState();
+    dp->ProducerRemoveWaiter(&waiter, &hss);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
+
+    dp->ProducerClose();
+  }
+
+  // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on consumer.
+  {
+    scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options));
+    // Add a waiter.
+    waiter.Init();
+    ASSERT_EQ(MOJO_RESULT_OK,
+              dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12,
+                                    nullptr));
+
+    // Close the producer.
+    dp->ProducerClose();
+
+    // It should be signaled.
+    uint32_t context = 0;
+    EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context));
+    EXPECT_EQ(12u, context);
+    hss = HandleSignalsState();
+    dp->ConsumerRemoveWaiter(&waiter, &hss);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
+
+    dp->ConsumerClose();
+  }
+}
+
 TEST(LocalDataPipeTest, BasicConsumerWaiting) {
   const MojoCreateDataPipeOptions options = {
       kSizeOfOptions,                           // |struct_size|.
@@ -411,7 +479,8 @@
         MOJO_RESULT_FAILED_PRECONDITION,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, &hss));
     EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Not yet readable.
     waiter.Init();
@@ -422,7 +491,8 @@
     hss = HandleSignalsState();
     dp->ConsumerRemoveWaiter(&waiter, &hss);
     EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Write two elements.
     int32_t elements[2] = {123, 456};
@@ -438,7 +508,8 @@
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Discard one element.
     num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
@@ -453,7 +524,8 @@
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Peek one element.
     elements[0] = -1;
@@ -473,7 +545,8 @@
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read one element.
     elements[0] = -1;
@@ -506,7 +579,8 @@
     hss = HandleSignalsState();
     dp->ConsumerRemoveWaiter(&waiter, &hss);
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Close the producer.
     dp->ProducerClose();
@@ -517,8 +591,10 @@
     EXPECT_EQ(
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss));
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read one element.
     elements[0] = -1;
@@ -537,8 +613,8 @@
     EXPECT_EQ(
         MOJO_RESULT_FAILED_PRECONDITION,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss));
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     dp->ConsumerClose();
   }
@@ -574,7 +650,8 @@
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read one element.
     // Request two in all-or-none mode, but only read one.
@@ -597,7 +674,8 @@
         MOJO_RESULT_ALREADY_EXISTS,
         dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read one element.
     // Request three, but not in all-or-none mode.
@@ -627,8 +705,8 @@
     EXPECT_EQ(56u, context);
     hss = HandleSignalsState();
     dp->ConsumerRemoveWaiter(&waiter, &hss);
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     dp->ConsumerClose();
   }
@@ -657,7 +735,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
   void* write_ptr = nullptr;
@@ -676,7 +755,8 @@
   hss = HandleSignalsState();
   dp->ProducerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // It shouldn't be readable yet either.
   waiter.Init();
@@ -687,7 +767,8 @@
   hss = HandleSignalsState();
   dp->ConsumerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   static_cast<int32_t*>(write_ptr)[0] = 123;
   EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(
@@ -700,7 +781,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // And readable.
   waiter.Init();
@@ -709,7 +791,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 4, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Start another two-phase write and check that it's readable even in the
   // middle of it.
@@ -728,7 +811,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // End the two-phase write without writing anything.
   EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u));
@@ -749,7 +833,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // But not readable.
   waiter.Init();
@@ -760,7 +845,8 @@
   hss = HandleSignalsState();
   dp->ConsumerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // End the two-phase read without reading anything.
   EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u));
@@ -772,7 +858,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   dp->ProducerClose();
   dp->ConsumerClose();
@@ -801,7 +888,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Not readable.
   waiter.Init();
@@ -812,7 +900,8 @@
   hss = HandleSignalsState();
   dp->ConsumerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   uint32_t num_bytes = static_cast<uint32_t>(sizeof(int32_t));
   int32_t element = 123;
@@ -828,7 +917,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 2, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Now readable.
   waiter.Init();
@@ -837,7 +927,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Overwrite that element.
   num_bytes = static_cast<uint32_t>(sizeof(int32_t));
@@ -854,7 +945,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // And still readable.
   waiter.Init();
@@ -863,7 +955,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Read that element.
   num_bytes = static_cast<uint32_t>(sizeof(int32_t));
@@ -881,7 +974,8 @@
       MOJO_RESULT_ALREADY_EXISTS,
       dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // No longer readable.
   waiter.Init();
@@ -892,7 +986,8 @@
   hss = HandleSignalsState();
   dp->ConsumerRemoveWaiter(&waiter, &hss);
   EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   dp->ProducerClose();
   dp->ConsumerClose();
diff --git a/mojo/edk/system/local_message_pipe_endpoint.cc b/mojo/edk/system/local_message_pipe_endpoint.cc
index 124241e..86d241c 100644
--- a/mojo/edk/system/local_message_pipe_endpoint.cc
+++ b/mojo/edk/system/local_message_pipe_endpoint.cc
@@ -137,7 +137,10 @@
     rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
     rv.satisfiable_signals |=
         MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE;
+  } else {
+    rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   }
+  rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
   return rv;
 }
 
diff --git a/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/mojo/edk/system/message_pipe_dispatcher_unittest.cc
index 8076a99..303ae6a 100644
--- a/mojo/edk/system/message_pipe_dispatcher_unittest.cc
+++ b/mojo/edk/system/message_pipe_dispatcher_unittest.cc
@@ -29,6 +29,10 @@
 namespace system {
 namespace {
 
+const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
+                                      MOJO_HANDLE_SIGNAL_WRITABLE |
+                                      MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+
 TEST(MessagePipeDispatcherTest, Basic) {
   test::Stopwatch stopwatch;
   int32_t buffer[1];
@@ -57,8 +61,7 @@
     EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-              hss.satisfiable_signals);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
     // Shouldn't need to remove the waiter (it was not added).
 
     // Add a readable waiter to |d0|, then make it readable (by writing to
@@ -78,8 +81,7 @@
     d0->RemoveWaiter(&w, &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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     // Try adding a readable waiter when already readable (from above).
     w.Init();
@@ -88,8 +90,7 @@
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
     // Shouldn't need to remove the waiter (it was not added).
 
     // Make |d0| no longer readable (by reading from it).
@@ -112,8 +113,7 @@
     hss = HandleSignalsState();
     d0->RemoveWaiter(&w, &hss);
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-              hss.satisfiable_signals);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     // Wait for non-zero, finite time for readability on |d0| (will time out).
     w.Init();
@@ -128,11 +128,25 @@
     hss = HandleSignalsState();
     d0->RemoveWaiter(&w, &hss);
     EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-              hss.satisfiable_signals);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
+
+    // Check the peer closed signal.
+    w.Init();
+    ASSERT_EQ(MOJO_RESULT_OK,
+              d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr));
+
+    // Close the peer.
+    EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
+
+    // It should be signaled.
+    EXPECT_EQ(MOJO_RESULT_OK, w.Wait(1000, &context));
+    EXPECT_EQ(12u, context);
+    hss = HandleSignalsState();
+    d0->RemoveWaiter(&w, &hss);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     EXPECT_EQ(MOJO_RESULT_OK, d0->Close());
-    EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
   }
 }
 
@@ -238,8 +252,7 @@
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     // Try reading from |d1|; should fail (nothing to read).
     buffer[0] = 0;
@@ -257,8 +270,10 @@
     hss = HandleSignalsState();
     EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 1, &hss));
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read from |d0|.
     buffer[0] = 0;
@@ -275,8 +290,10 @@
     hss = HandleSignalsState();
     EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss));
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+              hss.satisfiable_signals);
 
     // Read again from |d0|.
     buffer[0] = 0;
@@ -293,16 +310,16 @@
     hss = HandleSignalsState();
     EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss));
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     // Try waiting for writable on |d0|; should fail (unsatisfiable).
     w.Init();
     hss = HandleSignalsState();
     EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
               d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss));
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     // Try reading from |d0|; should fail (nothing to read and other end
     // closed).
@@ -374,8 +391,7 @@
     EXPECT_EQ(1u, context);
     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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     // Now |d1| is already readable. Try waiting for it again.
     {
@@ -390,8 +406,7 @@
     EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result);
     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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     // Consume what we wrote to |d0|.
     buffer[0] = 0;
@@ -420,8 +435,8 @@
     EXPECT_TRUE(did_wait);
     EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
     EXPECT_EQ(3u, context);
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
   }
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc
index 030084b..c700891 100644
--- a/mojo/edk/system/message_pipe_unittest.cc
+++ b/mojo/edk/system/message_pipe_unittest.cc
@@ -15,6 +15,10 @@
 namespace system {
 namespace {
 
+const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
+                                      MOJO_HANDLE_SIGNAL_WRITABLE |
+                                      MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+
 // Tests:
 //  - only default flags
 //  - reading messages from a port
@@ -335,8 +339,7 @@
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
             mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-            hss.satisfiable_signals);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
@@ -344,8 +347,7 @@
                                           MOJO_HANDLE_SIGNAL_WRITABLE,
                           0, &hss));
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-            hss.satisfiable_signals);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Not yet readable.
   waiter.Init();
@@ -355,8 +357,18 @@
   hss = HandleSignalsState();
   mp->RemoveWaiter(0, &waiter, &hss);
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-            hss.satisfiable_signals);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
+
+  // The peer is not closed.
+  waiter.Init();
+  ASSERT_EQ(
+      MOJO_RESULT_OK,
+      mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 2, nullptr));
+  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr));
+  hss = HandleSignalsState();
+  mp->RemoveWaiter(0, &waiter, &hss);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Write from port 0 (to port 1), to make port 1 readable.
   buffer[0] = 123456789;
@@ -368,11 +380,10 @@
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
-            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss));
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
@@ -381,36 +392,48 @@
                           0, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   // ... and still writable.
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
-            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss));
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Close port 0.
   mp->Close(0);
 
-  // Now port 1 should not be writable.
+  // Port 1 should be signaled with peer closed.
+  waiter.Init();
+  hss = HandleSignalsState();
+  EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 5, &hss));
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
+
+  // Port 1 should not be writable.
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
-            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss));
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss));
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // But it should still be readable.
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
-            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss));
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 7, &hss));
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
 
   // Read from port 1.
   buffer[0] = 0;
@@ -425,7 +448,7 @@
   waiter.Init();
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
-            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 6, nullptr));
+            mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, nullptr));
   EXPECT_EQ(0u, hss.satisfied_signals);
   EXPECT_EQ(0u, hss.satisfiable_signals);
 
@@ -460,8 +483,7 @@
     mp->RemoveWaiter(1, thread.waiter(), &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);
+    EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
     mp->Close(0);
     mp->Close(1);
@@ -493,6 +515,29 @@
   EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
   EXPECT_EQ(2u, context);
 
+  // Close to cancel waiter using peer closed signal.
+  {
+    scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal());
+    test::SimpleWaiterThread thread(&result, &context);
+
+    thread.waiter()->Init();
+    ASSERT_EQ(MOJO_RESULT_OK,
+              mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+                            3, nullptr));
+    thread.Start();
+
+    // Close port 1 first -- this should result in the waiter being cancelled.
+    mp->CancelAllWaiters(1);
+    mp->Close(1);
+
+    // Port 1 is closed, so |Dispatcher::RemoveWaiter()| wouldn't call into the
+    // |MessagePipe| to remove any waiter.
+
+    mp->Close(0);
+  }  // Joins |thread|.
+  EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
+  EXPECT_EQ(3u, context);
+
   // Close to make waiter un-wake-up-able.
   {
     scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal());
@@ -500,7 +545,7 @@
 
     thread.waiter()->Init();
     ASSERT_EQ(MOJO_RESULT_OK,
-              mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3,
+              mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 4,
                             nullptr));
     thread.Start();
 
@@ -511,14 +556,14 @@
 
     HandleSignalsState hss;
     mp->RemoveWaiter(1, thread.waiter(), &hss);
-    EXPECT_EQ(0u, hss.satisfied_signals);
-    EXPECT_EQ(0u, hss.satisfiable_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+    EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
     mp->CancelAllWaiters(1);
     mp->Close(1);
   }  // Joins |thread|.
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
-  EXPECT_EQ(3u, context);
+  EXPECT_EQ(4u, context);
 }
 
 }  // namespace
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
index 37e777e..f486152 100644
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc
+++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -62,8 +62,8 @@
     if (result != MOJO_RESULT_OK) {
       // It was closed, probably.
       CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION);
-      CHECK_EQ(hss.satisfied_signals, 0u);
-      CHECK_EQ(hss.satisfiable_signals, 0u);
+      CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
+      CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
       break;
     } else {
       CHECK((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
@@ -196,8 +196,8 @@
   HandleSignalsState hss;
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
             test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   mp->Close(0);
 
@@ -223,8 +223,9 @@
   // pipe before we do.
   CHECK_EQ(hss.satisfied_signals,
            MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
-  CHECK_EQ(hss.satisfiable_signals,
-           MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
+  CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
+                                        MOJO_HANDLE_SIGNAL_WRITABLE |
+                                        MOJO_HANDLE_SIGNAL_PEER_CLOSED);
 
   // It should have a shared buffer.
   std::string read_buffer(100, '\0');
@@ -272,8 +273,9 @@
            MOJO_RESULT_OK);
   CHECK_EQ(hss.satisfied_signals,
            MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
-  CHECK_EQ(hss.satisfiable_signals,
-           MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
+  CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
+                                        MOJO_HANDLE_SIGNAL_WRITABLE |
+                                        MOJO_HANDLE_SIGNAL_PEER_CLOSED);
 
   read_buffer = std::string(100, '\0');
   num_bytes = static_cast<uint32_t>(read_buffer.size());
@@ -377,8 +379,8 @@
   hss = HandleSignalsState();
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
             test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   mp->Close(0);
 
@@ -400,8 +402,9 @@
            MOJO_RESULT_OK);
   CHECK_EQ(hss.satisfied_signals,
            MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
-  CHECK_EQ(hss.satisfiable_signals,
-           MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
+  CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
+                                        MOJO_HANDLE_SIGNAL_WRITABLE |
+                                        MOJO_HANDLE_SIGNAL_PEER_CLOSED);
 
   std::string read_buffer(100, '\0');
   uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
@@ -485,8 +488,8 @@
   HandleSignalsState hss;
   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
             test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   mp->Close(0);
 
diff --git a/mojo/edk/system/remote_message_pipe_unittest.cc b/mojo/edk/system/remote_message_pipe_unittest.cc
index e3a320e..926ca0b 100644
--- a/mojo/edk/system/remote_message_pipe_unittest.cc
+++ b/mojo/edk/system/remote_message_pipe_unittest.cc
@@ -41,6 +41,10 @@
 namespace system {
 namespace {
 
+const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
+                                      MOJO_HANDLE_SIGNAL_WRITABLE |
+                                      MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+
 class RemoteMessagePipeTest : public testing::Test {
  public:
   RemoteMessagePipeTest() : io_thread_(base::TestIOThread::kAutoStart) {}
@@ -204,8 +208,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -233,8 +236,7 @@
   mp0->RemoveWaiter(0, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   buffer_size = static_cast<uint32_t>(sizeof(buffer));
   EXPECT_EQ(MOJO_RESULT_OK,
@@ -261,8 +263,44 @@
     hss = HandleSignalsState();
     mp1->RemoveWaiter(1, &waiter, &hss);
   }
-  EXPECT_EQ(0u, hss.satisfied_signals);
-  EXPECT_EQ(0u, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
+
+  // And MP 1, port 1.
+  mp1->Close(1);
+}
+
+TEST_F(RemoteMessagePipeTest, PeerClosed) {
+  Waiter waiter;
+  HandleSignalsState hss;
+  uint32_t context = 0;
+
+  // Connect message pipes. MP 0, port 1 will be attached to channel 0 and
+  // connected to MP 1, port 0, which will be attached to channel 1. This leaves
+  // MP 0, port 0 and MP 1, port 1 as the "user-facing" endpoints.
+
+  scoped_refptr<ChannelEndpoint> ep0;
+  scoped_refptr<MessagePipe> mp0(MessagePipe::CreateLocalProxy(&ep0));
+  scoped_refptr<ChannelEndpoint> ep1;
+  scoped_refptr<MessagePipe> mp1(MessagePipe::CreateProxyLocal(&ep1));
+  BootstrapChannelEndpoints(ep0, ep1);
+
+  // Close MP 0, port 0.
+  mp0->Close(0);
+
+  // Try to wait for MP 1, port 1 to be signaled with peer closed.
+  waiter.Init();
+  hss = HandleSignalsState();
+  MojoResult result =
+      mp1->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 101, &hss);
+  if (result == MOJO_RESULT_OK) {
+    EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context));
+    EXPECT_EQ(101u, context);
+    hss = HandleSignalsState();
+    mp1->RemoveWaiter(1, &waiter, &hss);
+  }
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   // And MP 1, port 1.
   mp1->Close(1);
@@ -314,8 +352,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   ChannelEndpointId received_id;
   buffer_size = static_cast<uint32_t>(sizeof(received_id));
@@ -349,8 +386,7 @@
   mp3->RemoveWaiter(0, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Make sure there's nothing on MP 0, port 0 or MP 1, port 1 or MP 2, port 0.
   buffer_size = static_cast<uint32_t>(sizeof(buffer));
@@ -396,7 +432,7 @@
   mp1->RemoveWaiter(1, &waiter, &hss);
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
             hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
+  EXPECT_EQ(kAllSignals | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
             hss.satisfiable_signals);
 
   // Make sure there's nothing on the other ports.
@@ -606,8 +642,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   char read_buffer[100] = {0};
@@ -651,8 +686,7 @@
   dispatcher->RemoveWaiter(&waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from the dispatcher.
   memset(read_buffer, 0, sizeof(read_buffer));
@@ -682,8 +716,7 @@
   local_mp->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from "local_mp", port 1.
   memset(read_buffer, 0, sizeof(read_buffer));
@@ -721,8 +754,7 @@
 
   hss = local_mp->GetHandleSignalsState(0);
   EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
-            hss.satisfiable_signals);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   // Write to the other end (|local_mp|, port 1), and then close it.
   EXPECT_EQ(
       MOJO_RESULT_OK,
@@ -731,8 +763,7 @@
   hss = local_mp->GetHandleSignalsState(0);
   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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   // Then the second message....
   EXPECT_EQ(
       MOJO_RESULT_OK,
@@ -741,8 +772,7 @@
   hss = local_mp->GetHandleSignalsState(0);
   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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
   // Then close it.
   local_mp->Close(1);
 
@@ -786,8 +816,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   char read_buffer[100] = {0};
@@ -811,8 +840,10 @@
 
   // |dispatcher| should already be readable and not writable.
   hss = dispatcher->GetHandleSignalsState();
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
   // So read from it.
   memset(read_buffer, 0, sizeof(read_buffer));
   read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer));
@@ -824,8 +855,10 @@
   EXPECT_STREQ(kHello, read_buffer);
   // It should still be readable.
   hss = dispatcher->GetHandleSignalsState();
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+            hss.satisfiable_signals);
   // So read from it.
   memset(read_buffer, 0, sizeof(read_buffer));
   read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer));
@@ -837,8 +870,8 @@
   EXPECT_STREQ(kWorld, read_buffer);
   // Now it should no longer be readable.
   hss = dispatcher->GetHandleSignalsState();
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals);
-  EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfiable_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
+  EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
 
   // Close everything that belongs to us.
   mp0->Close(0);
@@ -917,8 +950,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   char read_buffer[100] = {0};
@@ -1037,8 +1069,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   char read_buffer[100] = {0};
@@ -1175,8 +1206,7 @@
   mp1->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 1, port 1.
   char read_buffer[100] = {0};
@@ -1235,8 +1265,7 @@
   mp0->RemoveWaiter(0, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from MP 0, port 0.
   read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer));
@@ -1276,8 +1305,7 @@
   dispatcher->RemoveWaiter(&waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from the dispatcher.
   memset(read_buffer, 0, sizeof(read_buffer));
@@ -1307,8 +1335,7 @@
   local_mp->RemoveWaiter(1, &waiter, &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);
+  EXPECT_EQ(kAllSignals, hss.satisfiable_signals);
 
   // Read from "local_mp", port 1.
   memset(read_buffer, 0, sizeof(read_buffer));
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h
index 96441dc..9b1eedc 100644
--- a/mojo/public/c/system/types.h
+++ b/mojo/public/c/system/types.h
@@ -149,6 +149,7 @@
 //       |MOJO_RESULT_FAILED_PRECONDITION| if you attempt to wait on this.
 //   |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle.
 //   |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle.
+//   |MOJO_HANDLE_SIGNAL_PEER_CLOSED| - The peer handle is closed.
 
 typedef uint32_t MojoHandleSignals;
 
@@ -156,10 +157,12 @@
 const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0;
 const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0;
 const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1;
+const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2;
 #else
 #define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals)0)
 #define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals)1 << 0)
 #define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals)1 << 1)
+#define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((MojoHandleSignals)1 << 2)
 #endif
 
 // TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany.
diff --git a/mojo/public/dart/src/types.dart b/mojo/public/dart/src/types.dart
index 4353d74..1dc3572 100644
--- a/mojo/public/dart/src/types.dart
+++ b/mojo/public/dart/src/types.dart
@@ -122,6 +122,7 @@
   static const int NONE = 0;
   static const int READABLE = 1 << 0;
   static const int WRITABLE = 1 << 1;
+  static const int PEER_CLOSED = 1 << 2;
   static const int READWRITE = READABLE | WRITABLE;
 
   static bool isNone(int mask) => mask == NONE;
diff --git a/mojo/public/go/system/impl/mojo_types.go b/mojo/public/go/system/impl/mojo_types.go
index 01d518e..bd82898 100644
--- a/mojo/public/go/system/impl/mojo_types.go
+++ b/mojo/public/go/system/impl/mojo_types.go
@@ -57,6 +57,7 @@
 	MOJO_HANDLE_SIGNAL_NONE     MojoHandleSignals = 0
 	MOJO_HANDLE_SIGNAL_READABLE                   = 1 << 0
 	MOJO_HANDLE_SIGNAL_WRITABLE                   = 1 << 1
+	MOJO_HANDLE_SIGNAL_PEER_CLOSED                = 1 << 2
 
 	MOJO_WRITE_MESSAGE_FLAG_NONE       MojoWriteMessageFlags = 0
 	MOJO_READ_MESSAGE_FLAG_NONE        MojoReadMessageFlags  = 0
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
index d6c8e7d..746acc1 100644
--- a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
+++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -33,6 +33,7 @@
         private static final int FLAG_NONE = 0;
         private static final int FLAG_READABLE = 1 << 0;
         private static final int FLAG_WRITABLE = 1 << 1;
+        private static final int FLAG_PEER_CLOSED = 1 << 2;
 
         /**
          * Immutable signals.
@@ -64,6 +65,16 @@
         }
 
         /**
+         * Change the peer closed bit of this signal.
+         *
+         * @param peer_closed the new value of the peer closed bit.
+         * @return this.
+         */
+        public HandleSignals setPeerClosed(boolean closed) {
+            return setFlag(FLAG_PEER_CLOSED, closed);
+        }
+
+        /**
          * @return a signal with no bit set.
          */
         public static HandleSignals none() {
diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js
index 9dcb20f..4a67567 100644
--- a/mojo/public/js/core.js
+++ b/mojo/public/js/core.js
@@ -55,6 +55,7 @@
 var HANDLE_SIGNAL_NONE;
 var HANDLE_SIGNAL_READABLE;
 var HANDLE_SIGNAL_WRITABLE;
+var HANDLE_SIGNAL_PEER_CLOSED;
 
 /**
  * MojoCreateDataMessageOptions: Used to specify creation parameters for a data
diff --git a/mojo/public/python/mojo/c_core.pxd b/mojo/public/python/mojo/c_core.pxd
index 1526dfe..fe10fff 100644
--- a/mojo/public/python/mojo/c_core.pxd
+++ b/mojo/public/python/mojo/c_core.pxd
@@ -56,6 +56,7 @@
   const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE
   const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE
   const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE
+  const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED
 
   # functions.h
   MojoTimeTicks MojoGetTimeTicksNow()
diff --git a/mojo/public/python/mojo/system.pyx b/mojo/public/python/mojo/system.pyx
index 4507d4d..f0a814a 100644
--- a/mojo/public/python/mojo/system.pyx
+++ b/mojo/public/python/mojo/system.pyx
@@ -53,6 +53,7 @@
 HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE
 HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE
 HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE
+HANDLE_SIGNAL_PEER_CLOSED = c_core.MOJO_HANDLE_SIGNAL_PEER_CLOSED
 WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE
 READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE
 READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
diff --git a/mojo/python/tests/system_unittest.py b/mojo/python/tests/system_unittest.py
index 46eb0c2..7af62d8 100644
--- a/mojo/python/tests/system_unittest.py
+++ b/mojo/python/tests/system_unittest.py
@@ -45,6 +45,7 @@
     self.assertGreaterEqual(system.HANDLE_SIGNAL_NONE, 0)
     self.assertGreaterEqual(system.HANDLE_SIGNAL_READABLE, 0)
     self.assertGreaterEqual(system.HANDLE_SIGNAL_WRITABLE, 0)
+    self.assertGreaterEqual(system.HANDLE_SIGNAL_PEER_CLOSED, 0)
     self.assertGreaterEqual(system.WRITE_MESSAGE_FLAG_NONE, 0)
     self.assertGreaterEqual(system.READ_MESSAGE_FLAG_NONE, 0)
     self.assertGreaterEqual(system.READ_MESSAGE_FLAG_MAY_DISCARD, 0)