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