1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5
6 #include <sys/socket.h>
7
8 #include "base/compiler_specific.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_file.h"
11 #include "base/functional/bind.h"
12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/message_loop/message_pump_for_io.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/run_loop.h"
17 #include "base/task/current_thread.h"
18 #include "base/test/gtest_util.h"
19 #include "base/test/task_environment.h"
20 #include "build/build_config.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace base {
24
25 #if !BUILDFLAG(IS_NACL)
26
27 namespace {
28
29 class FdWatchControllerPosixTest : public testing::Test {
30 public:
31 FdWatchControllerPosixTest() = default;
32
33 FdWatchControllerPosixTest(const FdWatchControllerPosixTest&) = delete;
34 FdWatchControllerPosixTest& operator=(const FdWatchControllerPosixTest&) =
35 delete;
36
37 // testing::Test interface.
SetUp()38 void SetUp() override {
39 // Create a file descriptor. Doesn't need to be readable or writable,
40 // as we don't need to actually get any notifications.
41 // pipe() is just the easiest way to do it.
42 int pipefds[2];
43 int err = pipe(pipefds);
44 ASSERT_EQ(0, err);
45 read_fd_ = ScopedFD(pipefds[0]);
46 write_fd_ = ScopedFD(pipefds[1]);
47 }
48
TriggerReadEvent()49 void TriggerReadEvent() {
50 // Write from the other end of the pipe to trigger the event.
51 char c = '\0';
52 EXPECT_EQ(1, HANDLE_EINTR(write(write_fd_.get(), &c, 1)));
53 }
54
55 protected:
56 ScopedFD read_fd_;
57 ScopedFD write_fd_;
58 };
59
60 class TestHandler : public MessagePumpForIO::FdWatcher {
61 public:
OnFileCanReadWithoutBlocking(int fd)62 void OnFileCanReadWithoutBlocking(int fd) override {
63 watcher_to_delete_ = nullptr;
64 is_readable_ = true;
65 loop_->QuitWhenIdle();
66 }
OnFileCanWriteWithoutBlocking(int fd)67 void OnFileCanWriteWithoutBlocking(int fd) override {
68 watcher_to_delete_ = nullptr;
69 is_writable_ = true;
70 loop_->QuitWhenIdle();
71 }
set_run_loop(base::RunLoop * loop)72 void set_run_loop(base::RunLoop* loop) { loop_ = loop; }
73
74 bool is_readable_ = false;
75 bool is_writable_ = false;
76 raw_ptr<base::RunLoop> loop_;
77
78 // If set then the contained watcher will be deleted on notification.
79 std::unique_ptr<MessagePumpForIO::FdWatchController> watcher_to_delete_;
80 };
81
82 // Watcher that calls specified closures when read/write events occur. Verifies
83 // that each non-null closure passed to this class is called once and only once.
84 // Also resets the read event by reading from the FD.
85 class CallClosureHandler : public MessagePumpForIO::FdWatcher {
86 public:
CallClosureHandler(OnceClosure read_closure,OnceClosure write_closure)87 CallClosureHandler(OnceClosure read_closure, OnceClosure write_closure)
88 : read_closure_(std::move(read_closure)),
89 write_closure_(std::move(write_closure)) {}
90
~CallClosureHandler()91 ~CallClosureHandler() override {
92 EXPECT_TRUE(read_closure_.is_null());
93 EXPECT_TRUE(write_closure_.is_null());
94 }
95
SetReadClosure(OnceClosure read_closure)96 void SetReadClosure(OnceClosure read_closure) {
97 EXPECT_TRUE(read_closure_.is_null());
98 read_closure_ = std::move(read_closure);
99 }
100
SetWriteClosure(OnceClosure write_closure)101 void SetWriteClosure(OnceClosure write_closure) {
102 EXPECT_TRUE(write_closure_.is_null());
103 write_closure_ = std::move(write_closure);
104 }
105
106 // base::WatchableIOMessagePumpPosix::FdWatcher:
OnFileCanReadWithoutBlocking(int fd)107 void OnFileCanReadWithoutBlocking(int fd) override {
108 // Empty the pipe buffer to reset the event. Otherwise libevent
109 // implementation of MessageLoop may call the event handler again even if
110 // |read_closure_| below quits the RunLoop.
111 char c;
112 int result = HANDLE_EINTR(read(fd, &c, 1));
113 if (result == -1) {
114 PLOG(ERROR) << "read";
115 FAIL();
116 }
117 EXPECT_EQ(result, 1);
118
119 ASSERT_FALSE(read_closure_.is_null());
120 std::move(read_closure_).Run();
121 }
122
OnFileCanWriteWithoutBlocking(int fd)123 void OnFileCanWriteWithoutBlocking(int fd) override {
124 ASSERT_FALSE(write_closure_.is_null());
125 std::move(write_closure_).Run();
126 }
127
128 private:
129 OnceClosure read_closure_;
130 OnceClosure write_closure_;
131 };
132
TEST_F(FdWatchControllerPosixTest,FileDescriptorWatcherOutlivesMessageLoop)133 TEST_F(FdWatchControllerPosixTest, FileDescriptorWatcherOutlivesMessageLoop) {
134 // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
135 // This could happen when people use the Singleton pattern or atexit.
136 TestHandler handler;
137
138 // Arrange for watcher to live longer than message loop.
139 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
140 {
141 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
142
143 CurrentIOThread::Get()->WatchFileDescriptor(write_fd_.get(), true,
144 MessagePumpForIO::WATCH_WRITE,
145 &watcher, &handler);
146 // Don't run the message loop, just destroy it.
147 }
148
149 ASSERT_FALSE(handler.is_readable_);
150 ASSERT_FALSE(handler.is_writable_);
151 }
152
TEST_F(FdWatchControllerPosixTest,FileDescriptorWatcherDoubleStop)153 TEST_F(FdWatchControllerPosixTest, FileDescriptorWatcherDoubleStop) {
154 // Verify that it's ok to call StopWatchingFileDescriptor().
155
156 // Arrange for message loop to live longer than watcher.
157 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
158 {
159 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
160
161 TestHandler handler;
162 CurrentIOThread::Get()->WatchFileDescriptor(write_fd_.get(), true,
163 MessagePumpForIO::WATCH_WRITE,
164 &watcher, &handler);
165 ASSERT_TRUE(watcher.StopWatchingFileDescriptor());
166 ASSERT_TRUE(watcher.StopWatchingFileDescriptor());
167 }
168 }
169
TEST_F(FdWatchControllerPosixTest,FileDescriptorWatcherDeleteInCallback)170 TEST_F(FdWatchControllerPosixTest, FileDescriptorWatcherDeleteInCallback) {
171 // Verify that it is OK to delete the FileDescriptorWatcher from within a
172 // callback.
173 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
174
175 TestHandler handler;
176 base::RunLoop loop;
177 handler.set_run_loop(&loop);
178
179 handler.watcher_to_delete_ =
180 std::make_unique<MessagePumpForIO::FdWatchController>(FROM_HERE);
181
182 CurrentIOThread::Get()->WatchFileDescriptor(
183 write_fd_.get(), true, MessagePumpForIO::WATCH_WRITE,
184 handler.watcher_to_delete_.get(), &handler);
185 loop.Run();
186 }
187
188 // A watcher that owns its controller and will either delete itself or stop
189 // watching the FD after observing the specified event type.
190 class ReaderWriterHandler : public MessagePumpForIO::FdWatcher {
191 public:
192 enum Action {
193 // Just call StopWatchingFileDescriptor().
194 kStopWatching,
195 // Delete |this| and its owned controller.
196 kDelete,
197 };
198 enum ActWhen {
199 // Take the Action after observing a read event.
200 kOnReadEvent,
201 // Take the Action after observing a write event.
202 kOnWriteEvent,
203 };
204
ReaderWriterHandler(Action action,ActWhen when,OnceClosure idle_quit_closure)205 ReaderWriterHandler(Action action,
206 ActWhen when,
207 OnceClosure idle_quit_closure)
208 : action_(action),
209 when_(when),
210 controller_(FROM_HERE),
211 idle_quit_closure_(std::move(idle_quit_closure)) {}
212
213 ReaderWriterHandler(const ReaderWriterHandler&) = delete;
214 ReaderWriterHandler& operator=(const ReaderWriterHandler&) = delete;
215
216 // base::WatchableIOMessagePumpPosix::FdWatcher:
OnFileCanReadWithoutBlocking(int fd)217 void OnFileCanReadWithoutBlocking(int fd) override {
218 if (when_ == kOnReadEvent) {
219 DoAction();
220 } else {
221 char c;
222 EXPECT_EQ(1, HANDLE_EINTR(read(fd, &c, 1)));
223 }
224 }
225
OnFileCanWriteWithoutBlocking(int fd)226 void OnFileCanWriteWithoutBlocking(int fd) override {
227 if (when_ == kOnWriteEvent) {
228 DoAction();
229 } else {
230 char c = '\0';
231 EXPECT_EQ(1, HANDLE_EINTR(write(fd, &c, 1)));
232 }
233 }
234
controller()235 MessagePumpForIO::FdWatchController* controller() { return &controller_; }
236
237 private:
DoAction()238 void DoAction() {
239 OnceClosure idle_quit_closure = std::move(idle_quit_closure_);
240 if (action_ == kDelete) {
241 delete this;
242 } else if (action_ == kStopWatching) {
243 controller_.StopWatchingFileDescriptor();
244 }
245 std::move(idle_quit_closure).Run();
246 }
247
248 Action action_;
249 ActWhen when_;
250 MessagePumpForIO::FdWatchController controller_;
251 OnceClosure idle_quit_closure_;
252 };
253
254 class MessageLoopForIoPosixReadAndWriteTest
255 : public testing::TestWithParam<ReaderWriterHandler::Action> {
256 protected:
CreateSocketPair(ScopedFD * one,ScopedFD * two)257 bool CreateSocketPair(ScopedFD* one, ScopedFD* two) {
258 int fds[2];
259 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
260 return false;
261 one->reset(fds[0]);
262 two->reset(fds[1]);
263 return true;
264 }
265 };
266
267 INSTANTIATE_TEST_SUITE_P(StopWatchingOrDelete,
268 MessageLoopForIoPosixReadAndWriteTest,
269 testing::Values(ReaderWriterHandler::kStopWatching,
270 ReaderWriterHandler::kDelete));
271
272 // Test deleting or stopping watch after a read event for a watcher that is
273 // registered for both read and write.
TEST_P(MessageLoopForIoPosixReadAndWriteTest,AfterRead)274 TEST_P(MessageLoopForIoPosixReadAndWriteTest, AfterRead) {
275 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
276 ScopedFD one, two;
277 ASSERT_TRUE(CreateSocketPair(&one, &two));
278
279 RunLoop run_loop;
280 ReaderWriterHandler* handler =
281 new ReaderWriterHandler(GetParam(), ReaderWriterHandler::kOnReadEvent,
282 run_loop.QuitWhenIdleClosure());
283
284 // Trigger a read event on |one| by writing to |two|.
285 char c = '\0';
286 EXPECT_EQ(1, HANDLE_EINTR(write(two.get(), &c, 1)));
287
288 // The triggered read will cause the watcher action to run. |one| would
289 // also be immediately available for writing, so this should not cause a
290 // use-after-free on the |handler|.
291 CurrentIOThread::Get()->WatchFileDescriptor(
292 one.get(), true, MessagePumpForIO::WATCH_READ_WRITE,
293 handler->controller(), handler);
294 run_loop.Run();
295
296 if (GetParam() == ReaderWriterHandler::kStopWatching) {
297 delete handler;
298 }
299 }
300
301 // Test deleting or stopping watch after a write event for a watcher that is
302 // registered for both read and write.
TEST_P(MessageLoopForIoPosixReadAndWriteTest,AfterWrite)303 TEST_P(MessageLoopForIoPosixReadAndWriteTest, AfterWrite) {
304 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
305 ScopedFD one, two;
306 ASSERT_TRUE(CreateSocketPair(&one, &two));
307
308 RunLoop run_loop;
309 ReaderWriterHandler* handler =
310 new ReaderWriterHandler(GetParam(), ReaderWriterHandler::kOnWriteEvent,
311 run_loop.QuitWhenIdleClosure());
312
313 // Trigger two read events on |one| by writing to |two|. Because each read
314 // event only reads one char, |one| will be available for reading again after
315 // the first read event is handled.
316 char c = '\0';
317 EXPECT_EQ(1, HANDLE_EINTR(write(two.get(), &c, 1)));
318 EXPECT_EQ(1, HANDLE_EINTR(write(two.get(), &c, 1)));
319
320 // The triggered read and the immediate availability of |one| for writing
321 // should cause both the read and write watchers to be triggered. The
322 // |handler| will do its action in response to the write event, which should
323 // not trigger a use-after-free for the second read that was queued.
324 CurrentIOThread::Get()->WatchFileDescriptor(
325 one.get(), true, MessagePumpForIO::WATCH_READ_WRITE,
326 handler->controller(), handler);
327 run_loop.Run();
328
329 if (GetParam() == ReaderWriterHandler::kStopWatching) {
330 delete handler;
331 }
332 }
333
334 // Verify that basic readable notification works.
TEST_F(FdWatchControllerPosixTest,WatchReadable)335 TEST_F(FdWatchControllerPosixTest, WatchReadable) {
336 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
337 TestHandler handler;
338 base::RunLoop loop;
339 handler.set_run_loop(&loop);
340 // Watch the pipe for readability.
341 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
342 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
343 read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ,
344 &watcher, &handler));
345
346 // The pipe should not be readable when first created.
347 loop.RunUntilIdle();
348 ASSERT_FALSE(handler.is_readable_);
349 ASSERT_FALSE(handler.is_writable_);
350
351 TriggerReadEvent();
352
353 // We don't want to assume that the read fd becomes readable the
354 // instant a bytes is written, so Run until quit by an event.
355 loop.Run();
356
357 ASSERT_TRUE(handler.is_readable_);
358 ASSERT_FALSE(handler.is_writable_);
359 }
360
361 // Verify that watching a file descriptor for writability succeeds.
TEST_F(FdWatchControllerPosixTest,WatchWritable)362 TEST_F(FdWatchControllerPosixTest, WatchWritable) {
363 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
364 TestHandler handler;
365 base::RunLoop loop;
366
367 handler.set_run_loop(&loop);
368 // Watch the pipe for writability.
369 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
370 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
371 write_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_WRITE,
372 &watcher, &handler));
373
374 // We should not receive a writable notification until we process events.
375 ASSERT_FALSE(handler.is_readable_);
376 ASSERT_FALSE(handler.is_writable_);
377
378 // The pipe should be writable immediately, but wait for the quit closure
379 // anyway, to be sure.
380 loop.Run();
381
382 ASSERT_FALSE(handler.is_readable_);
383 ASSERT_TRUE(handler.is_writable_);
384 }
385
386 // Verify that RunUntilIdle() receives IO notifications.
TEST_F(FdWatchControllerPosixTest,RunUntilIdle)387 TEST_F(FdWatchControllerPosixTest, RunUntilIdle) {
388 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
389 TestHandler handler;
390 base::RunLoop loop;
391 handler.set_run_loop(&loop);
392 // Watch the pipe for readability.
393 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
394 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
395 read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ,
396 &watcher, &handler));
397
398 // The pipe should not be readable when first created.
399 loop.RunUntilIdle();
400 ASSERT_FALSE(handler.is_readable_);
401
402 TriggerReadEvent();
403
404 while (!handler.is_readable_)
405 loop.RunUntilIdle();
406 }
407
StopWatching(MessagePumpForIO::FdWatchController * controller,RunLoop * run_loop)408 void StopWatching(MessagePumpForIO::FdWatchController* controller,
409 RunLoop* run_loop) {
410 controller->StopWatchingFileDescriptor();
411 run_loop->Quit();
412 }
413
414 // Verify that StopWatchingFileDescriptor() works from an event handler.
TEST_F(FdWatchControllerPosixTest,StopFromHandler)415 TEST_F(FdWatchControllerPosixTest, StopFromHandler) {
416 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
417 RunLoop run_loop;
418 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
419 CallClosureHandler handler(BindOnce(&StopWatching, &watcher, &run_loop),
420 OnceClosure());
421
422 // Create persistent watcher.
423 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
424 read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ,
425 &watcher, &handler));
426
427 TriggerReadEvent();
428 run_loop.Run();
429
430 // Trigger the event again. The event handler should not be called again.
431 TriggerReadEvent();
432 RunLoop().RunUntilIdle();
433 }
434
435 // Verify that non-persistent watcher is called only once.
TEST_F(FdWatchControllerPosixTest,NonPersistentWatcher)436 TEST_F(FdWatchControllerPosixTest, NonPersistentWatcher) {
437 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
438
439 RunLoop run_loop;
440 CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure());
441
442 // Create a non-persistent watcher.
443 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
444 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
445 read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ,
446 &watcher, &handler));
447
448 TriggerReadEvent();
449 run_loop.Run();
450
451 // Trigger the event again. handler should not be called again.
452 TriggerReadEvent();
453 RunLoop().RunUntilIdle();
454 }
455
456 // Verify that persistent watcher is called every time the event is triggered.
TEST_F(FdWatchControllerPosixTest,PersistentWatcher)457 TEST_F(FdWatchControllerPosixTest, PersistentWatcher) {
458 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
459
460 RunLoop run_loop1;
461 CallClosureHandler handler(run_loop1.QuitClosure(), OnceClosure());
462
463 // Create persistent watcher.
464 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
465 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
466 read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ,
467 &watcher, &handler));
468
469 TriggerReadEvent();
470 run_loop1.Run();
471
472 RunLoop run_loop2;
473 handler.SetReadClosure(run_loop2.QuitClosure());
474
475 // Trigger the event again. handler should be called now, which will quit
476 // run_loop2.
477 TriggerReadEvent();
478 run_loop2.Run();
479 }
480
StopWatchingAndWatchAgain(MessagePumpForIO::FdWatchController * controller,int fd,MessagePumpForIO::FdWatcher * new_handler,RunLoop * run_loop)481 void StopWatchingAndWatchAgain(MessagePumpForIO::FdWatchController* controller,
482 int fd,
483 MessagePumpForIO::FdWatcher* new_handler,
484 RunLoop* run_loop) {
485 controller->StopWatchingFileDescriptor();
486
487 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
488 fd, /*persistent=*/true, MessagePumpForIO::WATCH_READ, controller,
489 new_handler));
490
491 run_loop->Quit();
492 }
493
494 // Verify that a watcher can be stopped and reused from an event handler.
TEST_F(FdWatchControllerPosixTest,StopAndRestartFromHandler)495 TEST_F(FdWatchControllerPosixTest, StopAndRestartFromHandler) {
496 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
497
498 RunLoop run_loop1;
499 RunLoop run_loop2;
500 CallClosureHandler handler2(run_loop2.QuitClosure(), OnceClosure());
501 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
502
503 CallClosureHandler handler1(BindOnce(&StopWatchingAndWatchAgain, &watcher,
504 read_fd_.get(), &handler2, &run_loop1),
505 OnceClosure());
506
507 // Create persistent watcher.
508 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
509 read_fd_.get(), /*persistent=*/true, MessagePumpForIO::WATCH_READ,
510 &watcher, &handler1));
511
512 TriggerReadEvent();
513 run_loop1.Run();
514
515 // Trigger the event again. handler2 should be called now, which will quit
516 // run_loop2
517 TriggerReadEvent();
518 run_loop2.Run();
519 }
520
521 // Verify that the pump properly handles a delayed task after an IO event.
TEST_F(FdWatchControllerPosixTest,IoEventThenTimer)522 TEST_F(FdWatchControllerPosixTest, IoEventThenTimer) {
523 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
524
525 RunLoop timer_run_loop;
526 env.GetMainThreadTaskRunner()->PostDelayedTask(
527 FROM_HERE, timer_run_loop.QuitClosure(), base::Milliseconds(10));
528
529 RunLoop watcher_run_loop;
530 CallClosureHandler handler(watcher_run_loop.QuitClosure(), OnceClosure());
531
532 // Create a non-persistent watcher.
533 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
534 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
535 read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ,
536 &watcher, &handler));
537
538 TriggerReadEvent();
539
540 // Normally the IO event will be received before the delayed task is
541 // executed, so this run loop will first handle the IO event and then quit on
542 // the timer.
543 timer_run_loop.Run();
544
545 // Run watcher_run_loop in case the IO event wasn't received before the
546 // delayed task.
547 watcher_run_loop.Run();
548 }
549
550 // Verify that the pipe can handle an IO event after a delayed task.
TEST_F(FdWatchControllerPosixTest,TimerThenIoEvent)551 TEST_F(FdWatchControllerPosixTest, TimerThenIoEvent) {
552 test::TaskEnvironment env(test::TaskEnvironment::MainThreadType::IO);
553
554 // Trigger read event from a delayed task.
555 env.GetMainThreadTaskRunner()->PostDelayedTask(
556 FROM_HERE,
557 BindOnce(&FdWatchControllerPosixTest::TriggerReadEvent, Unretained(this)),
558 Milliseconds(1));
559
560 RunLoop run_loop;
561 CallClosureHandler handler(run_loop.QuitClosure(), OnceClosure());
562
563 // Create a non-persistent watcher.
564 MessagePumpForIO::FdWatchController watcher(FROM_HERE);
565 ASSERT_TRUE(CurrentIOThread::Get()->WatchFileDescriptor(
566 read_fd_.get(), /*persistent=*/false, MessagePumpForIO::WATCH_READ,
567 &watcher, &handler));
568
569 run_loop.Run();
570 }
571
572 } // namespace
573
574 #endif // !BUILDFLAG(IS_NACL)
575
576 } // namespace base
577