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