| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |  | 
| 2 // Use of this source code is governed by a BSD-style license that can be |  | 
| 3 // found in the LICENSE file. |  | 
| 4 |  | 
| 5 #include <functional> |  | 
| 6 |  | 
| 7 #include "base/macros.h" |  | 
| 8 #include "base/memory/ref_counted.h" |  | 
| 9 #include "base/message_loop/message_loop.h" |  | 
| 10 #include "base/run_loop.h" |  | 
| 11 #include "base/single_thread_task_runner.h" |  | 
| 12 #include "base/threading/thread_task_runner_handle.h" |  | 
| 13 #include "mojo/edk/system/request_context.h" |  | 
| 14 #include "mojo/edk/test/mojo_test_base.h" |  | 
| 15 #include "mojo/public/c/system/functions.h" |  | 
| 16 #include "testing/gtest/include/gtest/gtest.h" |  | 
| 17 |  | 
| 18 namespace mojo { |  | 
| 19 namespace edk { |  | 
| 20 namespace { |  | 
| 21 |  | 
| 22 void IgnoreResult(uintptr_t context, |  | 
| 23                   MojoResult result, |  | 
| 24                   MojoHandleSignalsState signals, |  | 
| 25                   MojoWatchNotificationFlags flags) { |  | 
| 26 } |  | 
| 27 |  | 
| 28 // A test helper class for watching a handle. The WatchHelper instance is used |  | 
| 29 // as a watch context for a single watch callback. |  | 
| 30 class WatchHelper { |  | 
| 31  public: |  | 
| 32   using Callback = |  | 
| 33       std::function<void(MojoResult result, MojoHandleSignalsState state)>; |  | 
| 34 |  | 
| 35   WatchHelper() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |  | 
| 36   ~WatchHelper() { |  | 
| 37     CHECK(!watching_); |  | 
| 38   } |  | 
| 39 |  | 
| 40   void Watch(MojoHandle handle, |  | 
| 41              MojoHandleSignals signals, |  | 
| 42              const Callback& callback) { |  | 
| 43     CHECK(!watching_); |  | 
| 44 |  | 
| 45     handle_ = handle; |  | 
| 46     callback_ = callback; |  | 
| 47     watching_ = true; |  | 
| 48     CHECK_EQ(MOJO_RESULT_OK, MojoWatch(handle_, signals, &WatchHelper::OnNotify, |  | 
| 49                                        reinterpret_cast<uintptr_t>(this))); |  | 
| 50   } |  | 
| 51 |  | 
| 52   bool is_watching() const { return watching_; } |  | 
| 53 |  | 
| 54   void Cancel() { |  | 
| 55     CHECK_EQ(MOJO_RESULT_OK, |  | 
| 56              MojoCancelWatch(handle_, reinterpret_cast<uintptr_t>(this))); |  | 
| 57     CHECK(watching_); |  | 
| 58     watching_ = false; |  | 
| 59   } |  | 
| 60 |  | 
| 61  private: |  | 
| 62   static void OnNotify(uintptr_t context, |  | 
| 63                        MojoResult result, |  | 
| 64                        MojoHandleSignalsState state, |  | 
| 65                        MojoWatchNotificationFlags flags) { |  | 
| 66     WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); |  | 
| 67     watcher->task_runner_->PostTask( |  | 
| 68         FROM_HERE, |  | 
| 69         base::Bind(&NotifyOnMainThread, context, result, state, flags)); |  | 
| 70   } |  | 
| 71 |  | 
| 72   static void NotifyOnMainThread(uintptr_t context, |  | 
| 73                                  MojoResult result, |  | 
| 74                                  MojoHandleSignalsState state, |  | 
| 75                                  MojoWatchNotificationFlags flags) { |  | 
| 76     WatchHelper* watcher = reinterpret_cast<WatchHelper*>(context); |  | 
| 77     CHECK(watcher->watching_); |  | 
| 78     if (result == MOJO_RESULT_CANCELLED) |  | 
| 79       watcher->watching_ = false; |  | 
| 80     watcher->callback_(result, state); |  | 
| 81   } |  | 
| 82 |  | 
| 83   scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |  | 
| 84   bool watching_ = false; |  | 
| 85   MojoHandle handle_; |  | 
| 86   Callback callback_; |  | 
| 87 |  | 
| 88   DISALLOW_COPY_AND_ASSIGN(WatchHelper); |  | 
| 89 }; |  | 
| 90 |  | 
| 91 class WatchTest : public test::MojoTestBase { |  | 
| 92  public: |  | 
| 93   WatchTest() {} |  | 
| 94   ~WatchTest() override {} |  | 
| 95 |  | 
| 96  protected: |  | 
| 97 |  | 
| 98  private: |  | 
| 99   base::MessageLoop message_loop_; |  | 
| 100 |  | 
| 101   DISALLOW_COPY_AND_ASSIGN(WatchTest); |  | 
| 102 }; |  | 
| 103 |  | 
| 104 TEST_F(WatchTest, NotifyBasic) { |  | 
| 105   MojoHandle a, b; |  | 
| 106   CreateMessagePipe(&a, &b); |  | 
| 107 |  | 
| 108   base::RunLoop loop; |  | 
| 109   WatchHelper b_watcher; |  | 
| 110   b_watcher.Watch( |  | 
| 111       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 112       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 113         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 114         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 115                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 116         EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 117         loop.Quit(); |  | 
| 118       }); |  | 
| 119 |  | 
| 120   WriteMessage(a, "Hello!"); |  | 
| 121   loop.Run(); |  | 
| 122 |  | 
| 123   EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 124   b_watcher.Cancel(); |  | 
| 125 |  | 
| 126   CloseHandle(a); |  | 
| 127   CloseHandle(b); |  | 
| 128 } |  | 
| 129 |  | 
| 130 TEST_F(WatchTest, NotifyUnsatisfiable) { |  | 
| 131   MojoHandle a, b; |  | 
| 132   CreateMessagePipe(&a, &b); |  | 
| 133 |  | 
| 134   base::RunLoop loop; |  | 
| 135   WatchHelper b_watcher; |  | 
| 136   b_watcher.Watch( |  | 
| 137       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 138       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 139         EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); |  | 
| 140         EXPECT_EQ(0u, |  | 
| 141                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 142         EXPECT_EQ(0u, |  | 
| 143                   state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 144         EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 145         loop.Quit(); |  | 
| 146       }); |  | 
| 147 |  | 
| 148   CloseHandle(a); |  | 
| 149   loop.Run(); |  | 
| 150 |  | 
| 151   b_watcher.Cancel(); |  | 
| 152 |  | 
| 153   CloseHandle(b); |  | 
| 154 } |  | 
| 155 |  | 
| 156 TEST_F(WatchTest, NotifyCancellation) { |  | 
| 157   MojoHandle a, b; |  | 
| 158   CreateMessagePipe(&a, &b); |  | 
| 159 |  | 
| 160   base::RunLoop loop; |  | 
| 161   WatchHelper b_watcher; |  | 
| 162   b_watcher.Watch( |  | 
| 163       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 164       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 165         EXPECT_EQ(MOJO_RESULT_CANCELLED, result); |  | 
| 166         EXPECT_EQ(0u, state.satisfied_signals); |  | 
| 167         EXPECT_EQ(0u, state.satisfiable_signals); |  | 
| 168         EXPECT_FALSE(b_watcher.is_watching()); |  | 
| 169         loop.Quit(); |  | 
| 170       }); |  | 
| 171 |  | 
| 172   CloseHandle(b); |  | 
| 173   loop.Run(); |  | 
| 174 |  | 
| 175   CloseHandle(a); |  | 
| 176 } |  | 
| 177 |  | 
| 178 TEST_F(WatchTest, InvalidArguemnts) { |  | 
| 179   MojoHandle a, b; |  | 
| 180   CreateMessagePipe(&a, &b); |  | 
| 181 |  | 
| 182   uintptr_t context = reinterpret_cast<uintptr_t>(this); |  | 
| 183   EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 184                                       &IgnoreResult, context)); |  | 
| 185 |  | 
| 186   // Can't cancel a watch that doesn't exist. |  | 
| 187   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(a, ~context)); |  | 
| 188   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(b, context)); |  | 
| 189 |  | 
| 190   CloseHandle(a); |  | 
| 191   CloseHandle(b); |  | 
| 192 |  | 
| 193   // Can't watch a handle that doesn't exist. |  | 
| 194   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, |  | 
| 195             MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |  | 
| 196   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, |  | 
| 197             MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |  | 
| 198 } |  | 
| 199 |  | 
| 200 TEST_F(WatchTest, NoDuplicateContext) { |  | 
| 201   MojoHandle a, b; |  | 
| 202   CreateMessagePipe(&a, &b); |  | 
| 203 |  | 
| 204   // Try to add the same watch twice; should fail. |  | 
| 205   uintptr_t context = reinterpret_cast<uintptr_t>(this); |  | 
| 206   EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 207                                       &IgnoreResult, context)); |  | 
| 208   EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, |  | 
| 209       MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |  | 
| 210 |  | 
| 211   // Cancel and add it again; should be OK. |  | 
| 212   EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(a, context)); |  | 
| 213   EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 214                                       &IgnoreResult, context)); |  | 
| 215 |  | 
| 216   CloseHandle(a); |  | 
| 217   CloseHandle(b); |  | 
| 218 } |  | 
| 219 |  | 
| 220 TEST_F(WatchTest, MultipleWatches) { |  | 
| 221   MojoHandle a, b; |  | 
| 222   CreateMessagePipe(&a, &b); |  | 
| 223 |  | 
| 224   // Add multiple watchers to |b| and see that they are both notified by a |  | 
| 225   // single write to |a|. |  | 
| 226   base::RunLoop loop; |  | 
| 227   int expected_notifications = 2; |  | 
| 228   auto on_readable = [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 229     EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 230     EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 231               state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 232     EXPECT_GT(expected_notifications, 0); |  | 
| 233     if (--expected_notifications == 0) |  | 
| 234       loop.Quit(); |  | 
| 235   }; |  | 
| 236   WatchHelper watcher1; |  | 
| 237   WatchHelper watcher2; |  | 
| 238   watcher1.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); |  | 
| 239   watcher2.Watch(b, MOJO_HANDLE_SIGNAL_READABLE, on_readable); |  | 
| 240 |  | 
| 241   WriteMessage(a, "Ping!"); |  | 
| 242   loop.Run(); |  | 
| 243 |  | 
| 244   watcher1.Cancel(); |  | 
| 245   watcher2.Cancel(); |  | 
| 246 |  | 
| 247   CloseHandle(a); |  | 
| 248   CloseHandle(b); |  | 
| 249 } |  | 
| 250 |  | 
| 251 TEST_F(WatchTest, WatchWhileSatisfied) { |  | 
| 252   MojoHandle a, b; |  | 
| 253   CreateMessagePipe(&a, &b); |  | 
| 254 |  | 
| 255   // Write to |a| and then start watching |b|. The callback should be invoked |  | 
| 256   // synchronously. |  | 
| 257   WriteMessage(a, "hey"); |  | 
| 258   bool signaled = false; |  | 
| 259   WatchHelper b_watcher; |  | 
| 260   base::RunLoop loop; |  | 
| 261   b_watcher.Watch( |  | 
| 262       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 263       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 264         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 265         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 266                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 267         signaled = true; |  | 
| 268         loop.Quit(); |  | 
| 269       }); |  | 
| 270   loop.Run(); |  | 
| 271   EXPECT_TRUE(signaled); |  | 
| 272   b_watcher.Cancel(); |  | 
| 273 |  | 
| 274   CloseHandle(a); |  | 
| 275   CloseHandle(b); |  | 
| 276 } |  | 
| 277 |  | 
| 278 TEST_F(WatchTest, WatchWhileUnsatisfiable) { |  | 
| 279   MojoHandle a, b; |  | 
| 280   CreateMessagePipe(&a, &b); |  | 
| 281 |  | 
| 282   // Close |a| and then try to watch |b|. MojoWatch() should fail. |  | 
| 283   CloseHandle(a); |  | 
| 284   uintptr_t context = reinterpret_cast<uintptr_t>(this); |  | 
| 285   EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, |  | 
| 286             MojoWatch(b, MOJO_HANDLE_SIGNAL_READABLE, &IgnoreResult, context)); |  | 
| 287 |  | 
| 288   CloseHandle(b); |  | 
| 289 } |  | 
| 290 |  | 
| 291 TEST_F(WatchTest, RespondFromCallback) { |  | 
| 292   MojoHandle a, b; |  | 
| 293   CreateMessagePipe(&a, &b); |  | 
| 294 |  | 
| 295   // Watch |a| and |b|. Write to |a|, then write to |b| from within the callback |  | 
| 296   // which notifies it of the available message. |  | 
| 297   const std::string kTestMessage = "hello worlds."; |  | 
| 298   base::RunLoop loop; |  | 
| 299   WatchHelper b_watcher; |  | 
| 300   b_watcher.Watch( |  | 
| 301       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 302       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 303         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 304         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 305                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 306         EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 307 |  | 
| 308         // Echo a's message back to it. |  | 
| 309         WriteMessage(b, ReadMessage(b)); |  | 
| 310       }); |  | 
| 311 |  | 
| 312   WatchHelper a_watcher; |  | 
| 313   a_watcher.Watch( |  | 
| 314       a, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 315       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 316         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 317         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 318                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 319         EXPECT_TRUE(a_watcher.is_watching()); |  | 
| 320 |  | 
| 321         // Expect to receive back the message that was originally sent to |b|. |  | 
| 322         EXPECT_EQ(kTestMessage, ReadMessage(a)); |  | 
| 323 |  | 
| 324         loop.Quit(); |  | 
| 325       }); |  | 
| 326 |  | 
| 327   WriteMessage(a, kTestMessage); |  | 
| 328   loop.Run(); |  | 
| 329 |  | 
| 330   a_watcher.Cancel(); |  | 
| 331   b_watcher.Cancel(); |  | 
| 332 |  | 
| 333   CloseHandle(a); |  | 
| 334   CloseHandle(b); |  | 
| 335 } |  | 
| 336 |  | 
| 337 TEST_F(WatchTest, WatchDataPipeConsumer) { |  | 
| 338   MojoHandle a, b; |  | 
| 339   CreateDataPipe(&a, &b, 64); |  | 
| 340 |  | 
| 341   base::RunLoop loop; |  | 
| 342   WatchHelper b_watcher; |  | 
| 343   b_watcher.Watch( |  | 
| 344       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 345       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 346         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 347         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 348                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 349         EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 350         loop.Quit(); |  | 
| 351       }); |  | 
| 352 |  | 
| 353   WriteData(a, "Hello!"); |  | 
| 354   loop.Run(); |  | 
| 355 |  | 
| 356   EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 357   b_watcher.Cancel(); |  | 
| 358 |  | 
| 359   CloseHandle(a); |  | 
| 360   CloseHandle(b); |  | 
| 361 } |  | 
| 362 |  | 
| 363 TEST_F(WatchTest, WatchDataPipeProducer) { |  | 
| 364   MojoHandle a, b; |  | 
| 365   CreateDataPipe(&a, &b, 8); |  | 
| 366 |  | 
| 367   // Fill the pipe to capacity so writes will block. |  | 
| 368   WriteData(a, "xxxxxxxx"); |  | 
| 369 |  | 
| 370   base::RunLoop loop; |  | 
| 371   WatchHelper a_watcher; |  | 
| 372   a_watcher.Watch( |  | 
| 373       a, MOJO_HANDLE_SIGNAL_WRITABLE, |  | 
| 374       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 375         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 376         EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, |  | 
| 377                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE); |  | 
| 378         EXPECT_TRUE(a_watcher.is_watching()); |  | 
| 379         loop.Quit(); |  | 
| 380       }); |  | 
| 381 |  | 
| 382   EXPECT_EQ("xxxxxxxx", ReadData(b, 8)); |  | 
| 383   loop.Run(); |  | 
| 384 |  | 
| 385   EXPECT_TRUE(a_watcher.is_watching()); |  | 
| 386   a_watcher.Cancel(); |  | 
| 387 |  | 
| 388   CloseHandle(a); |  | 
| 389   CloseHandle(b); |  | 
| 390 } |  | 
| 391 |  | 
| 392 TEST_F(WatchTest, WakeUpSelfWithinWatchCallback) { |  | 
| 393   MojoHandle a, b; |  | 
| 394   CreateMessagePipe(&a, &b); |  | 
| 395 |  | 
| 396   int expected_notifications = 2; |  | 
| 397   base::RunLoop loop; |  | 
| 398   WatchHelper b_watcher; |  | 
| 399   b_watcher.Watch( |  | 
| 400       b, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 401       [&] (MojoResult result, MojoHandleSignalsState state) { |  | 
| 402         EXPECT_EQ(MOJO_RESULT_OK, result); |  | 
| 403         EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 404                   state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE); |  | 
| 405         EXPECT_TRUE(b_watcher.is_watching()); |  | 
| 406         if (--expected_notifications == 0) { |  | 
| 407           loop.Quit(); |  | 
| 408         } else { |  | 
| 409           // Trigger b's watch again from within this callback. This should be |  | 
| 410           // safe to do. |  | 
| 411           WriteMessage(a, "hey"); |  | 
| 412         } |  | 
| 413       }); |  | 
| 414 |  | 
| 415   WriteMessage(a, "hey hey hey"); |  | 
| 416   loop.Run(); |  | 
| 417 |  | 
| 418   b_watcher.Cancel(); |  | 
| 419 |  | 
| 420   CloseHandle(a); |  | 
| 421   CloseHandle(b); |  | 
| 422 } |  | 
| 423 |  | 
| 424 TEST_F(WatchTest, NestedCancellation) { |  | 
| 425   // Verifies that cancellations in nested system request contexts preempt |  | 
| 426   // other notifications for the same watcher. This tests against the condition |  | 
| 427   // hit by http://crbug.com/622298. |  | 
| 428 |  | 
| 429   MojoHandle a, b, c, d; |  | 
| 430   CreateMessagePipe(&a, &b); |  | 
| 431   CreateMessagePipe(&c, &d); |  | 
| 432 |  | 
| 433   base::RunLoop loop; |  | 
| 434   bool a_watcher_run = false; |  | 
| 435   WatchHelper a_watcher; |  | 
| 436   a_watcher.Watch( |  | 
| 437       a, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 438       [&](MojoResult result, MojoHandleSignalsState state) { |  | 
| 439         a_watcher_run = true; |  | 
| 440       }); |  | 
| 441 |  | 
| 442   WatchHelper c_watcher; |  | 
| 443   c_watcher.Watch( |  | 
| 444       c, MOJO_HANDLE_SIGNAL_READABLE, |  | 
| 445       [&](MojoResult result, MojoHandleSignalsState state) { |  | 
| 446         // This will trigger a notification on |a_watcher| above to be executed |  | 
| 447         // once this handler finishes running... |  | 
| 448         CloseHandle(b); |  | 
| 449 |  | 
| 450         // ...but this should prevent that notification from dispatching because |  | 
| 451         // |a_watcher| is now cancelled. |  | 
| 452         a_watcher.Cancel(); |  | 
| 453 |  | 
| 454         loop.Quit(); |  | 
| 455       }); |  | 
| 456 |  | 
| 457   { |  | 
| 458     // Force "system" notifications for the synchronous behavior required to |  | 
| 459     // test this case. |  | 
| 460     mojo::edk::RequestContext request_context( |  | 
| 461         mojo::edk::RequestContext::Source::SYSTEM); |  | 
| 462 |  | 
| 463     // Trigger the |c_watcher| callback above. |  | 
| 464     CloseHandle(d); |  | 
| 465   } |  | 
| 466 |  | 
| 467   loop.Run(); |  | 
| 468 |  | 
| 469   EXPECT_FALSE(a_watcher.is_watching()); |  | 
| 470   EXPECT_FALSE(a_watcher_run); |  | 
| 471 |  | 
| 472   c_watcher.Cancel(); |  | 
| 473 |  | 
| 474   CloseHandle(a); |  | 
| 475   CloseHandle(c); |  | 
| 476 } |  | 
| 477 |  | 
| 478 }  // namespace |  | 
| 479 }  // namespace edk |  | 
| 480 }  // namespace mojo |  | 
| OLD | NEW | 
|---|