• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()29 MainMessageLoopExternalPump::MainMessageLoopExternalPump()
30     : is_active_(false), reentrancy_detected_(false) {
31   DCHECK(!g_external_message_pump);
32   g_external_message_pump = this;
33 }
34 
~MainMessageLoopExternalPump()35 MainMessageLoopExternalPump::~MainMessageLoopExternalPump() {
36   g_external_message_pump = nullptr;
37 }
38 
Get()39 MainMessageLoopExternalPump* MainMessageLoopExternalPump::Get() {
40   return g_external_message_pump;
41 }
42 
OnScheduleWork(int64 delay_ms)43 void 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()67 void MainMessageLoopExternalPump::OnTimerTimeout() {
68   REQUIRE_MAIN_THREAD();
69 
70   KillTimer();
71   DoWork();
72 }
73 
DoWork()74 void 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()86 bool 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