• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/darwin/message_loop_darwin.h"
6
7#include <CoreFoundation/CFRunLoop.h>
8#include <Foundation/Foundation.h>
9
10#include "flutter/fml/logging.h"
11
12namespace fml {
13
14static constexpr CFTimeInterval kDistantFuture = 1.0e10;
15
16MessageLoopDarwin::MessageLoopDarwin()
17    : running_(false), loop_((CFRunLoopRef)CFRetain(CFRunLoopGetCurrent())) {
18  FML_DCHECK(loop_ != nullptr);
19
20  // Setup the delayed wake source.
21  CFRunLoopTimerContext timer_context = {
22      .info = this,
23  };
24  delayed_wake_timer_.Reset(
25      CFRunLoopTimerCreate(kCFAllocatorDefault, kDistantFuture /* fire date */,
26                           HUGE_VAL /* interval */, 0 /* flags */, 0 /* order */,
27                           reinterpret_cast<CFRunLoopTimerCallBack>(&MessageLoopDarwin::OnTimerFire)
28                           /* callout */,
29                           &timer_context /* context */));
30  FML_DCHECK(delayed_wake_timer_ != nullptr);
31  CFRunLoopAddTimer(loop_, delayed_wake_timer_, kCFRunLoopCommonModes);
32}
33
34MessageLoopDarwin::~MessageLoopDarwin() {
35  CFRunLoopTimerInvalidate(delayed_wake_timer_);
36  CFRunLoopRemoveTimer(loop_, delayed_wake_timer_, kCFRunLoopCommonModes);
37}
38
39void MessageLoopDarwin::Run() {
40  FML_DCHECK(loop_ == CFRunLoopGetCurrent());
41
42  running_ = true;
43
44  while (running_) {
45    @autoreleasepool {
46      int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kDistantFuture, YES);
47      if (result == kCFRunLoopRunStopped || result == kCFRunLoopRunFinished) {
48        // This handles the case where the loop is terminated using
49        // CoreFoundation APIs.
50        @autoreleasepool {
51          RunExpiredTasksNow();
52        }
53        running_ = false;
54      }
55    }
56  }
57}
58
59void MessageLoopDarwin::Terminate() {
60  running_ = false;
61  CFRunLoopStop(loop_);
62}
63
64void MessageLoopDarwin::WakeUp(fml::TimePoint time_point) {
65  // Rearm the timer. The time bases used by CoreFoundation and FXL are
66  // different and must be accounted for.
67  CFRunLoopTimerSetNextFireDate(
68      delayed_wake_timer_,
69      CFAbsoluteTimeGetCurrent() + (time_point - fml::TimePoint::Now()).ToSecondsF());
70}
71
72void MessageLoopDarwin::OnTimerFire(CFRunLoopTimerRef timer, MessageLoopDarwin* loop) {
73  @autoreleasepool {
74    // RunExpiredTasksNow rearms the timer as appropriate via a call to WakeUp.
75    loop->RunExpiredTasksNow();
76  }
77}
78
79}  // namespace fml
80