1 // Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #include "tests/shared/browser/main_message_loop_external_pump.h" 6 7 #include <climits> 8 9 #include "include/cef_app.h" 10 #include "include/wrapper/cef_helpers.h" 11 #include "tests/shared/browser/main_message_loop.h" 12 13 namespace client { 14 15 namespace { 16 17 // Special timer delay placeholder value. Intentionally 32-bit for Windows and 18 // OS X platform API compatibility. 19 const int32 kTimerDelayPlaceholder = INT_MAX; 20 21 // The maximum number of milliseconds we're willing to wait between calls to 22 // DoWork(). 23 const int64 kMaxTimerDelay = 1000 / 30; // 30fps 24 25 client::MainMessageLoopExternalPump* g_external_message_pump = nullptr; 26 27 } // namespace 28 MainMessageLoopExternalPump()29MainMessageLoopExternalPump::MainMessageLoopExternalPump() 30 : is_active_(false), reentrancy_detected_(false) { 31 DCHECK(!g_external_message_pump); 32 g_external_message_pump = this; 33 } 34 ~MainMessageLoopExternalPump()35MainMessageLoopExternalPump::~MainMessageLoopExternalPump() { 36 g_external_message_pump = nullptr; 37 } 38 Get()39MainMessageLoopExternalPump* MainMessageLoopExternalPump::Get() { 40 return g_external_message_pump; 41 } 42 OnScheduleWork(int64 delay_ms)43void MainMessageLoopExternalPump::OnScheduleWork(int64 delay_ms) { 44 REQUIRE_MAIN_THREAD(); 45 46 if (delay_ms == kTimerDelayPlaceholder && IsTimerPending()) { 47 // Don't set the maximum timer requested from DoWork() if a timer event is 48 // currently pending. 49 return; 50 } 51 52 KillTimer(); 53 54 if (delay_ms <= 0) { 55 // Execute the work immediately. 56 DoWork(); 57 } else { 58 // Never wait longer than the maximum allowed time. 59 if (delay_ms > kMaxTimerDelay) 60 delay_ms = kMaxTimerDelay; 61 62 // Results in call to OnTimerTimeout() after the specified delay. 63 SetTimer(delay_ms); 64 } 65 } 66 OnTimerTimeout()67void MainMessageLoopExternalPump::OnTimerTimeout() { 68 REQUIRE_MAIN_THREAD(); 69 70 KillTimer(); 71 DoWork(); 72 } 73 DoWork()74void MainMessageLoopExternalPump::DoWork() { 75 const bool was_reentrant = PerformMessageLoopWork(); 76 if (was_reentrant) { 77 // Execute the remaining work as soon as possible. 78 OnScheduleMessagePumpWork(0); 79 } else if (!IsTimerPending()) { 80 // Schedule a timer event at the maximum allowed time. This may be dropped 81 // in OnScheduleWork() if another timer event is already in-flight. 82 OnScheduleMessagePumpWork(kTimerDelayPlaceholder); 83 } 84 } 85 PerformMessageLoopWork()86bool MainMessageLoopExternalPump::PerformMessageLoopWork() { 87 if (is_active_) { 88 // When CefDoMessageLoopWork() is called there may be various callbacks 89 // (such as paint and IPC messages) that result in additional calls to this 90 // method. If re-entrancy is detected we must repost a request again to the 91 // owner thread to ensure that the discarded call is executed in the future. 92 reentrancy_detected_ = true; 93 return false; 94 } 95 96 reentrancy_detected_ = false; 97 98 is_active_ = true; 99 CefDoMessageLoopWork(); 100 is_active_ = false; 101 102 // |reentrancy_detected_| may have changed due to re-entrant calls to this 103 // method. 104 return reentrancy_detected_; 105 } 106 107 } // namespace client 108