Flutter Engine
message_loop_fuchsia.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "flutter/fml/platform/fuchsia/message_loop_fuchsia.h"
6 
7 #include <lib/async-loop/default.h>
8 #include <lib/async/cpp/task.h>
9 #include <lib/async/default.h>
10 #include <lib/zx/time.h>
11 #include <zircon/status.h>
12 
13 #include "flutter/fml/platform/fuchsia/task_observers.h"
14 
15 namespace fml {
16 
17 namespace {
18 
19 // See comment on `ExecuteAfterTaskObservers` for explanation.
20 static void LoopEpilogue(async_loop_t*, void*) {
22 }
23 
24 constexpr async_loop_config_t kLoopConfig = {
25  .make_default_for_current_thread = false,
26  .epilogue = &LoopEpilogue,
27 };
28 
29 } // namespace
30 
31 MessageLoopFuchsia::MessageLoopFuchsia() : loop_(&kLoopConfig) {
32  async_set_default_dispatcher(loop_.dispatcher());
33 
34  zx_status_t timer_status =
35  zx::timer::create(ZX_TIMER_SLACK_LATE, ZX_CLOCK_MONOTONIC, &timer_);
36  FML_CHECK(timer_status == ZX_OK)
37  << "MessageLoopFuchsia failed to create timer; status="
38  << zx_status_get_string(timer_status);
39 }
40 
41 MessageLoopFuchsia::~MessageLoopFuchsia() {
42  // It is only safe to unset the current thread's default dispatcher if it is
43  // already pointing to this loop.
44  if (async_get_default_dispatcher() == loop_.dispatcher()) {
45  async_set_default_dispatcher(nullptr);
46  }
47 }
48 
49 void MessageLoopFuchsia::Run() {
50  timer_wait_ = std::make_unique<async::Wait>(
51  timer_.get(), ZX_TIMER_SIGNALED, 0,
52  [this](async_dispatcher_t* dispatcher, async::Wait* wait,
53  zx_status_t status, const zx_packet_signal_t* signal) {
54  if (status == ZX_ERR_CANCELED) {
55  return;
56  }
57  FML_CHECK(signal->observed & ZX_TIMER_SIGNALED);
58 
59  // Cancel the timer now, because `RunExpiredTasksNow` might not re-arm
60  // the timer. That would leave the timer in a signalled state and it
61  // would trigger the async::Wait again immediately, creating a busy
62  // loop.
63  //
64  // NOTE: It is not neccesary to synchronize this with the timer_.set()
65  // call below, even though WakeUp() can be called from any thread and
66  // thus timer_.set() can run in parallel with this timer_.cancel().
67  //
68  // Zircon will synchronize the 2 syscalls internally, and the Wait loop
69  // here is resilient to cancel() and set() being called in any order.
70  timer_.cancel();
71 
72  // Run the tasks, which may or may not re-arm the timer for the future.
73  RunExpiredTasksNow();
74 
75  // Kick off the next iteration of the timer wait loop.
76  zx_status_t wait_status = wait->Begin(loop_.dispatcher());
77  FML_CHECK(wait_status == ZX_OK)
78  << "MessageLoopFuchsia::WakeUp failed to wait for timer; status="
79  << zx_status_get_string(wait_status);
80  });
81 
82  // Kick off the first iteration of the timer wait loop.
83  zx_status_t wait_status = timer_wait_->Begin(loop_.dispatcher());
84  FML_CHECK(wait_status == ZX_OK)
85  << "MessageLoopFuchsia::WakeUp failed to wait for timer; status="
86  << zx_status_get_string(wait_status);
87 
88  // Kick off the underlying async loop that services the timer wait in addition
89  // to other tasks and waits queued on its `async_dispatcher_t`.
90  loop_.Run();
91 
92  // Ensure any pending waits on the timer are properly canceled.
93  if (timer_wait_->is_pending()) {
94  timer_wait_->Cancel();
95  timer_.cancel();
96  }
97 }
98 
99 void MessageLoopFuchsia::Terminate() {
100  loop_.Quit();
101 }
102 
103 void MessageLoopFuchsia::WakeUp(fml::TimePoint time_point) {
104  constexpr zx::duration kZeroSlack(0);
105  zx::time due_time(time_point.ToEpochDelta().ToNanoseconds());
106 
107  zx_status_t timer_status = timer_.set(due_time, kZeroSlack);
108  FML_CHECK(timer_status == ZX_OK)
109  << "MessageLoopFuchsia::WakeUp failed to set timer; status="
110  << zx_status_get_string(timer_status);
111 }
112 
113 } // namespace fml
void ExecuteAfterTaskObservers()
TimeDelta ToEpochDelta() const
Definition: time_point.h:47
Definition: ascii_trie.cc:9
constexpr int64_t ToNanoseconds() const
Definition: time_delta.h:61
#define FML_CHECK(condition)
Definition: logging.h:68