message_pump_win.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. // Copyright (c) 2012 The Chromium 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. #include "base/message_loop/message_pump_win.h"
  5. #include <algorithm>
  6. #include <cstdint>
  7. #include <type_traits>
  8. #include "base/auto_reset.h"
  9. #include "base/bind.h"
  10. #include "base/cxx17_backports.h"
  11. #include "base/debug/alias.h"
  12. #include "base/feature_list.h"
  13. #include "base/metrics/histogram_macros.h"
  14. #include "base/numerics/safe_conversions.h"
  15. #include "base/trace_event/base_tracing.h"
  16. #include "base/tracing_buildflags.h"
  17. #if BUILDFLAG(ENABLE_BASE_TRACING)
  18. #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_message_pump.pbzero.h"
  19. #endif // BUILDFLAG(ENABLE_BASE_TRACING)
  20. namespace base {
  21. namespace {
  22. enum MessageLoopProblems {
  23. MESSAGE_POST_ERROR,
  24. COMPLETION_POST_ERROR,
  25. SET_TIMER_ERROR,
  26. RECEIVED_WM_QUIT_ERROR,
  27. MESSAGE_LOOP_PROBLEM_MAX,
  28. };
  29. // Returns the number of milliseconds before |next_task_time|, clamped between
  30. // zero and the biggest DWORD value (or INFINITE if |next_task_time.is_max()|).
  31. // Optionally, a recent value of Now() may be passed in to avoid resampling it.
  32. DWORD GetSleepTimeoutMs(TimeTicks next_task_time,
  33. TimeTicks recent_now = TimeTicks()) {
  34. // Shouldn't need to sleep or install a timer when there's pending immediate
  35. // work.
  36. DCHECK(!next_task_time.is_null());
  37. if (next_task_time.is_max())
  38. return INFINITE;
  39. auto now = recent_now.is_null() ? TimeTicks::Now() : recent_now;
  40. auto timeout_ms = (next_task_time - now).InMillisecondsRoundedUp();
  41. // A saturated_cast with an unsigned destination automatically clamps negative
  42. // values at zero.
  43. static_assert(!std::is_signed<DWORD>::value, "DWORD is unexpectedly signed");
  44. return saturated_cast<DWORD>(timeout_ms);
  45. }
  46. } // namespace
  47. // Message sent to get an additional time slice for pumping (processing) another
  48. // task (a series of such messages creates a continuous task pump).
  49. static const int kMsgHaveWork = WM_USER + 1;
  50. //-----------------------------------------------------------------------------
  51. // MessagePumpWin public:
  52. MessagePumpWin::MessagePumpWin() = default;
  53. MessagePumpWin::~MessagePumpWin() = default;
  54. void MessagePumpWin::Run(Delegate* delegate) {
  55. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  56. RunState run_state(delegate);
  57. if (run_state_)
  58. run_state.is_nested = true;
  59. AutoReset<RunState*> auto_reset_run_state(&run_state_, &run_state);
  60. DoRunLoop();
  61. }
  62. void MessagePumpWin::Quit() {
  63. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  64. DCHECK(run_state_);
  65. run_state_->should_quit = true;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // MessagePumpForUI public:
  69. MessagePumpForUI::MessagePumpForUI() {
  70. bool succeeded = message_window_.Create(
  71. BindRepeating(&MessagePumpForUI::MessageCallback, Unretained(this)));
  72. DCHECK(succeeded);
  73. }
  74. MessagePumpForUI::~MessagePumpForUI() = default;
  75. void MessagePumpForUI::ScheduleWork() {
  76. // This is the only MessagePumpForUI method which can be called outside of
  77. // |bound_thread_|.
  78. bool not_scheduled = false;
  79. if (!work_scheduled_.compare_exchange_strong(not_scheduled, true))
  80. return; // Someone else continued the pumping.
  81. // Make sure the MessagePump does some work for us.
  82. const BOOL ret = ::PostMessage(message_window_.hwnd(), kMsgHaveWork, 0, 0);
  83. if (ret)
  84. return; // There was room in the Window Message queue.
  85. // We have failed to insert a have-work message, so there is a chance that we
  86. // will starve tasks/timers while sitting in a nested run loop. Nested
  87. // loops only look at Windows Message queues, and don't look at *our* task
  88. // queues, etc., so we might not get a time slice in such. :-(
  89. // We could abort here, but the fear is that this failure mode is plausibly
  90. // common (queue is full, of about 2000 messages), so we'll do a near-graceful
  91. // recovery. Nested loops are pretty transient (we think), so this will
  92. // probably be recoverable.
  93. // Clarify that we didn't really insert.
  94. work_scheduled_ = false;
  95. UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
  96. MESSAGE_LOOP_PROBLEM_MAX);
  97. TRACE_EVENT_INSTANT0("base", "Chrome.MessageLoopProblem.MESSAGE_POST_ERROR",
  98. TRACE_EVENT_SCOPE_THREAD);
  99. }
  100. void MessagePumpForUI::ScheduleDelayedWork(
  101. const Delegate::NextWorkInfo& next_work_info) {
  102. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  103. // Since this is always called from |bound_thread_|, there is almost always
  104. // nothing to do as the loop is already running. When the loop becomes idle,
  105. // it will typically WaitForWork() in DoRunLoop() with the timeout provided by
  106. // DoWork(). The only alternative to this is entering a native nested loop
  107. // (e.g. modal dialog) under a ScopedNestableTaskAllower, in which case
  108. // HandleWorkMessage() will be invoked when the system picks up kMsgHaveWork
  109. // and it will ScheduleNativeTimer() if it's out of immediate work. However,
  110. // in that alternate scenario : it's possible for a Windows native work item
  111. // (e.g. https://docs.microsoft.com/en-us/windows/desktop/winmsg/using-hooks)
  112. // to wake the native nested loop and PostDelayedTask() to the current thread
  113. // from it. This is the only case where we must install/adjust the native
  114. // timer from ScheduleDelayedWork() because if we don't, the native loop will
  115. // go back to sleep, unaware of the new |delayed_work_time|.
  116. // See MessageLoopTest.PostDelayedTaskFromSystemPump for an example.
  117. // TODO(gab): This could potentially be replaced by a ForegroundIdleProc hook
  118. // if Windows ends up being the only platform requiring ScheduleDelayedWork().
  119. if (in_native_loop_ && !work_scheduled_) {
  120. ScheduleNativeTimer(next_work_info);
  121. }
  122. }
  123. void MessagePumpForUI::AddObserver(Observer* observer) {
  124. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  125. observers_.AddObserver(observer);
  126. }
  127. void MessagePumpForUI::RemoveObserver(Observer* observer) {
  128. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  129. observers_.RemoveObserver(observer);
  130. }
  131. //-----------------------------------------------------------------------------
  132. // MessagePumpForUI private:
  133. bool MessagePumpForUI::MessageCallback(
  134. UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
  135. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  136. switch (message) {
  137. case kMsgHaveWork:
  138. HandleWorkMessage();
  139. break;
  140. case WM_TIMER:
  141. if (wparam == reinterpret_cast<UINT_PTR>(this))
  142. HandleTimerMessage();
  143. break;
  144. }
  145. return false;
  146. }
  147. void MessagePumpForUI::DoRunLoop() {
  148. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  149. // IF this was just a simple PeekMessage() loop (servicing all possible work
  150. // queues), then Windows would try to achieve the following order according
  151. // to MSDN documentation about PeekMessage with no filter):
  152. // * Sent messages
  153. // * Posted messages
  154. // * Sent messages (again)
  155. // * WM_PAINT messages
  156. // * WM_TIMER messages
  157. //
  158. // Summary: none of the above classes is starved, and sent messages has twice
  159. // the chance of being processed (i.e., reduced service time).
  160. for (;;) {
  161. // If we do any work, we may create more messages etc., and more work may
  162. // possibly be waiting in another task group. When we (for example)
  163. // ProcessNextWindowsMessage(), there is a good chance there are still more
  164. // messages waiting. On the other hand, when any of these methods return
  165. // having done no work, then it is pretty unlikely that calling them again
  166. // quickly will find any work to do. Finally, if they all say they had no
  167. // work, then it is a good time to consider sleeping (waiting) for more
  168. // work.
  169. in_native_loop_ = false;
  170. bool more_work_is_plausible = ProcessNextWindowsMessage();
  171. in_native_loop_ = false;
  172. if (run_state_->should_quit)
  173. break;
  174. Delegate::NextWorkInfo next_work_info = run_state_->delegate->DoWork();
  175. in_native_loop_ = false;
  176. more_work_is_plausible |= next_work_info.is_immediate();
  177. if (run_state_->should_quit)
  178. break;
  179. if (installed_native_timer_) {
  180. // As described in ScheduleNativeTimer(), the native timer is only
  181. // installed and needed while in a nested native loop. If it is installed,
  182. // it means the above work entered such a loop. Having now resumed, the
  183. // native timer is no longer needed.
  184. KillNativeTimer();
  185. }
  186. if (more_work_is_plausible)
  187. continue;
  188. more_work_is_plausible = run_state_->delegate->DoIdleWork();
  189. // DoIdleWork() shouldn't end up in native nested loops and thus shouldn't
  190. // have any chance of reinstalling a native timer.
  191. DCHECK(!in_native_loop_);
  192. DCHECK(!installed_native_timer_);
  193. if (run_state_->should_quit)
  194. break;
  195. if (more_work_is_plausible)
  196. continue;
  197. WaitForWork(next_work_info);
  198. }
  199. }
  200. void MessagePumpForUI::WaitForWork(Delegate::NextWorkInfo next_work_info) {
  201. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  202. // Wait until a message is available, up to the time needed by the timer
  203. // manager to fire the next set of timers.
  204. DWORD wait_flags = MWMO_INPUTAVAILABLE;
  205. for (DWORD delay = GetSleepTimeoutMs(next_work_info.delayed_run_time,
  206. next_work_info.recent_now);
  207. delay != 0; delay = GetSleepTimeoutMs(next_work_info.delayed_run_time)) {
  208. run_state_->delegate->BeforeWait();
  209. // Tell the optimizer to retain these values to simplify analyzing hangs.
  210. base::debug::Alias(&delay);
  211. base::debug::Alias(&wait_flags);
  212. DWORD result = MsgWaitForMultipleObjectsEx(0, nullptr, delay, QS_ALLINPUT,
  213. wait_flags);
  214. if (WAIT_OBJECT_0 == result) {
  215. // A WM_* message is available.
  216. // If a parent child relationship exists between windows across threads
  217. // then their thread inputs are implicitly attached.
  218. // This causes the MsgWaitForMultipleObjectsEx API to return indicating
  219. // that messages are ready for processing (Specifically, mouse messages
  220. // intended for the child window may appear if the child window has
  221. // capture).
  222. // The subsequent PeekMessages call may fail to return any messages thus
  223. // causing us to enter a tight loop at times.
  224. // The code below is a workaround to give the child window
  225. // some time to process its input messages by looping back to
  226. // MsgWaitForMultipleObjectsEx above when there are no messages for the
  227. // current thread.
  228. // As in ProcessNextWindowsMessage().
  229. auto scoped_do_work_item = run_state_->delegate->BeginWorkItem();
  230. {
  231. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("base"),
  232. "MessagePumpForUI::WaitForWork GetQueueStatus");
  233. if (HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE)
  234. return;
  235. }
  236. {
  237. MSG msg;
  238. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("base"),
  239. "MessagePumpForUI::WaitForWork PeekMessage");
  240. if (::PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE))
  241. return;
  242. }
  243. // We know there are no more messages for this thread because PeekMessage
  244. // has returned false. Reset |wait_flags| so that we wait for a *new*
  245. // message.
  246. wait_flags = 0;
  247. }
  248. DCHECK_NE(WAIT_FAILED, result) << GetLastError();
  249. }
  250. }
  251. void MessagePumpForUI::HandleWorkMessage() {
  252. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  253. // The kMsgHaveWork message was consumed by a native loop, we must assume
  254. // we're in one until DoRunLoop() gets control back.
  255. in_native_loop_ = true;
  256. // If we are being called outside of the context of Run, then don't try to do
  257. // any work. This could correspond to a MessageBox call or something of that
  258. // sort.
  259. if (!run_state_) {
  260. // Since we handled a kMsgHaveWork message, we must still update this flag.
  261. work_scheduled_ = false;
  262. return;
  263. }
  264. // Let whatever would have run had we not been putting messages in the queue
  265. // run now. This is an attempt to make our dummy message not starve other
  266. // messages that may be in the Windows message queue.
  267. ProcessPumpReplacementMessage();
  268. Delegate::NextWorkInfo next_work_info = run_state_->delegate->DoWork();
  269. if (next_work_info.is_immediate()) {
  270. ScheduleWork();
  271. } else {
  272. run_state_->delegate->BeforeWait();
  273. ScheduleNativeTimer(next_work_info);
  274. }
  275. }
  276. void MessagePumpForUI::HandleTimerMessage() {
  277. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  278. // ::KillTimer doesn't remove pending WM_TIMER messages from the queue,
  279. // explicitly ignore the last WM_TIMER message in that case to avoid handling
  280. // work from here when DoRunLoop() is active (which could result in scheduling
  281. // work from two places at once). Note: we're still fine in the event that a
  282. // second native nested loop is entered before such a dead WM_TIMER message is
  283. // discarded because ::SetTimer merely resets the timer if invoked twice with
  284. // the same id.
  285. if (!installed_native_timer_)
  286. return;
  287. // We only need to fire once per specific delay, another timer may be
  288. // scheduled below but we're done with this one.
  289. KillNativeTimer();
  290. // If we are being called outside of the context of Run, then don't do
  291. // anything. This could correspond to a MessageBox call or something of
  292. // that sort.
  293. if (!run_state_)
  294. return;
  295. Delegate::NextWorkInfo next_work_info = run_state_->delegate->DoWork();
  296. if (next_work_info.is_immediate()) {
  297. ScheduleWork();
  298. } else {
  299. run_state_->delegate->BeforeWait();
  300. ScheduleNativeTimer(next_work_info);
  301. }
  302. }
  303. void MessagePumpForUI::ScheduleNativeTimer(
  304. Delegate::NextWorkInfo next_work_info) {
  305. DCHECK(!next_work_info.is_immediate());
  306. DCHECK(in_native_loop_);
  307. // Do not redundantly set the same native timer again if it was already set.
  308. // This can happen when a nested native loop goes idle with pending delayed
  309. // tasks, then gets woken up by an immediate task, and goes back to idle with
  310. // the same pending delay. No need to kill the native timer if there is
  311. // already one but the |delayed_run_time| has changed as ::SetTimer reuses the
  312. // same id and will replace and reset the existing timer.
  313. if (installed_native_timer_ &&
  314. *installed_native_timer_ == next_work_info.delayed_run_time) {
  315. return;
  316. }
  317. if (next_work_info.delayed_run_time.is_max())
  318. return;
  319. // We do not use native Windows timers in general as they have a poor, 10ms,
  320. // granularity. Instead we rely on MsgWaitForMultipleObjectsEx's
  321. // high-resolution timeout to sleep without timers in WaitForWork(). However,
  322. // when entering a nested native ::GetMessage() loop (e.g. native modal
  323. // windows) under a ScopedNestableTaskAllower, we have to rely on a native
  324. // timer when HandleWorkMessage() runs out of immediate work. Since
  325. // ScopedNestableTaskAllower invokes ScheduleWork() : we are guaranteed that
  326. // HandleWorkMessage() will be called after entering a nested native loop that
  327. // should process application tasks. But once HandleWorkMessage() is out of
  328. // immediate work, ::SetTimer() is used to guarantee we are invoked again
  329. // should the next delayed task expire before the nested native loop ends. The
  330. // native timer being unnecessary once we return to our DoRunLoop(), we
  331. // ::KillTimer when it resumes (nested native loops should be rare so we're
  332. // not worried about ::SetTimer<=>::KillTimer churn).
  333. // TODO(gab): The long-standing legacy dependency on the behavior of
  334. // ScopedNestableTaskAllower is unfortunate, would be nice to make this a
  335. // MessagePump concept (instead of requiring impls to invoke ScheduleWork()
  336. // one-way and no-op DoWork() the other way).
  337. UINT delay_msec = strict_cast<UINT>(GetSleepTimeoutMs(
  338. next_work_info.delayed_run_time, next_work_info.recent_now));
  339. if (delay_msec == 0) {
  340. ScheduleWork();
  341. } else {
  342. // TODO(gab): ::SetTimer()'s documentation claims it does this for us.
  343. // Consider removing this safety net.
  344. delay_msec =
  345. clamp(delay_msec, UINT(USER_TIMER_MINIMUM), UINT(USER_TIMER_MAXIMUM));
  346. // Tell the optimizer to retain the delay to simplify analyzing hangs.
  347. base::debug::Alias(&delay_msec);
  348. const UINT_PTR ret =
  349. ::SetTimer(message_window_.hwnd(), reinterpret_cast<UINT_PTR>(this),
  350. delay_msec, nullptr);
  351. if (ret) {
  352. installed_native_timer_ = next_work_info.delayed_run_time;
  353. return;
  354. }
  355. // This error is likely similar to MESSAGE_POST_ERROR (i.e. native queue is
  356. // full). Since we only use ScheduleNativeTimer() in native nested loops
  357. // this likely means this pump will not be given a chance to run application
  358. // tasks until the nested loop completes.
  359. UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
  360. MESSAGE_LOOP_PROBLEM_MAX);
  361. TRACE_EVENT_INSTANT0("base", "Chrome.MessageLoopProblem.SET_TIMER_ERROR",
  362. TRACE_EVENT_SCOPE_THREAD);
  363. }
  364. }
  365. void MessagePumpForUI::KillNativeTimer() {
  366. DCHECK(installed_native_timer_);
  367. const bool success =
  368. ::KillTimer(message_window_.hwnd(), reinterpret_cast<UINT_PTR>(this));
  369. DPCHECK(success);
  370. installed_native_timer_.reset();
  371. }
  372. bool MessagePumpForUI::ProcessNextWindowsMessage() {
  373. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  374. MSG msg;
  375. bool has_msg = false;
  376. bool more_work_is_plausible = false;
  377. {
  378. // ::PeekMessage() may process sent and/or internal messages (regardless of
  379. // |had_messages| as ::GetQueueStatus() is an optimistic check that may
  380. // racily have missed an incoming event -- it doesn't hurt to have empty
  381. // internal units of work when ::PeekMessage turns out to be a no-op).
  382. // Instantiate |scoped_do_work| ahead of GetQueueStatus() so that
  383. // trace events it emits fully outscope GetQueueStatus' events
  384. // (GetQueueStatus() itself not being expected to do work; it's fine to use
  385. // only one ScopedDoWorkItem for both calls -- we trace them independently
  386. // just in case internal work stalls).
  387. auto scoped_do_work_item = run_state_->delegate->BeginWorkItem();
  388. {
  389. // Individually trace ::GetQueueStatus and ::PeekMessage because sampling
  390. // profiler is hinting that we're spending a surprising amount of time
  391. // with these on top of the stack. Tracing will be able to tell us whether
  392. // this is a bias of sampling profiler (e.g. kernel takes ::GetQueueStatus
  393. // as an opportunity to swap threads and is more likely to schedule the
  394. // sampling profiler's thread while the sampled thread is swapped out on
  395. // this frame).
  396. TRACE_EVENT0(
  397. TRACE_DISABLED_BY_DEFAULT("base"),
  398. "MessagePumpForUI::ProcessNextWindowsMessage GetQueueStatus");
  399. DWORD queue_status = ::GetQueueStatus(QS_SENDMESSAGE);
  400. // If there are sent messages in the queue then PeekMessage internally
  401. // dispatches the message and returns false. We return true in this case
  402. // to ensure that the message loop peeks again instead of calling
  403. // MsgWaitForMultipleObjectsEx.
  404. if (HIWORD(queue_status) & QS_SENDMESSAGE)
  405. more_work_is_plausible = true;
  406. }
  407. {
  408. // PeekMessage can run a message if there are sent messages, trace that
  409. // and emit the boolean param to see if it ever janks independently (ref.
  410. // comment on GetQueueStatus).
  411. TRACE_EVENT(
  412. TRACE_DISABLED_BY_DEFAULT("base"),
  413. "MessagePumpForUI::ProcessNextWindowsMessage PeekMessage",
  414. [&](perfetto::EventContext ctx) {
  415. perfetto::protos::pbzero::ChromeMessagePump* msg_pump_data =
  416. ctx.event()->set_chrome_message_pump();
  417. msg_pump_data->set_sent_messages_in_queue(more_work_is_plausible);
  418. });
  419. has_msg = ::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE;
  420. }
  421. }
  422. if (has_msg)
  423. more_work_is_plausible |= ProcessMessageHelper(msg);
  424. return more_work_is_plausible;
  425. }
  426. bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
  427. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  428. if (msg.message == WM_QUIT) {
  429. // WM_QUIT is the standard way to exit a ::GetMessage() loop. Our
  430. // MessageLoop has its own quit mechanism, so WM_QUIT is generally
  431. // unexpected.
  432. UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem",
  433. RECEIVED_WM_QUIT_ERROR, MESSAGE_LOOP_PROBLEM_MAX);
  434. return true;
  435. }
  436. // While running our main message pump, we discard kMsgHaveWork messages.
  437. if (msg.message == kMsgHaveWork && msg.hwnd == message_window_.hwnd())
  438. return ProcessPumpReplacementMessage();
  439. auto scoped_do_work_item = run_state_->delegate->BeginWorkItem();
  440. TRACE_EVENT("base,toplevel", "MessagePumpForUI DispatchMessage",
  441. [&](perfetto::EventContext ctx) {
  442. ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>()
  443. ->set_chrome_message_pump_for_ui()
  444. ->set_message_id(msg.message);
  445. });
  446. for (Observer& observer : observers_)
  447. observer.WillDispatchMSG(msg);
  448. ::TranslateMessage(&msg);
  449. ::DispatchMessage(&msg);
  450. for (Observer& observer : observers_)
  451. observer.DidDispatchMSG(msg);
  452. return true;
  453. }
  454. bool MessagePumpForUI::ProcessPumpReplacementMessage() {
  455. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  456. // When we encounter a kMsgHaveWork message, this method is called to peek and
  457. // process a replacement message. The goal is to make the kMsgHaveWork as non-
  458. // intrusive as possible, even though a continuous stream of such messages are
  459. // posted. This method carefully peeks a message while there is no chance for
  460. // a kMsgHaveWork to be pending, then resets the |have_work_| flag (allowing a
  461. // replacement kMsgHaveWork to possibly be posted), and finally dispatches
  462. // that peeked replacement. Note that the re-post of kMsgHaveWork may be
  463. // asynchronous to this thread!!
  464. MSG msg;
  465. bool have_message = false;
  466. {
  467. // Note: Ideally this call wouldn't process sent-messages (as we already did
  468. // that in the PeekMessage call that lead to receiving this kMsgHaveWork),
  469. // but there's no way to specify this (omitting PM_QS_SENDMESSAGE as in
  470. // crrev.com/791043 doesn't do anything). Hence this call must be considered
  471. // as a potential work item.
  472. TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("base"),
  473. "MessagePumpForUI::ProcessPumpReplacementMessage PeekMessage");
  474. auto scoped_do_work_item = run_state_->delegate->BeginWorkItem();
  475. have_message = ::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE;
  476. }
  477. // Expect no message or a message different than kMsgHaveWork.
  478. DCHECK(!have_message || kMsgHaveWork != msg.message ||
  479. msg.hwnd != message_window_.hwnd());
  480. // Since we discarded a kMsgHaveWork message, we must update the flag.
  481. DCHECK(work_scheduled_);
  482. work_scheduled_ = false;
  483. // We don't need a special time slice if we didn't |have_message| to process.
  484. if (!have_message)
  485. return false;
  486. if (msg.message == WM_QUIT) {
  487. // If we're in a nested ::GetMessage() loop then we must let that loop see
  488. // the WM_QUIT in order for it to exit. If we're in DoRunLoop then the re-
  489. // posted WM_QUIT will be either ignored, or handled, by
  490. // ProcessMessageHelper() called directly from ProcessNextWindowsMessage().
  491. ::PostQuitMessage(static_cast<int>(msg.wParam));
  492. // Note: we *must not* ScheduleWork() here as WM_QUIT is a low-priority
  493. // message on Windows (it is only returned by ::PeekMessage() when idle) :
  494. // https://blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453. As
  495. // such posting a kMsgHaveWork message via ScheduleWork() would cause an
  496. // infinite loop (kMsgHaveWork message handled first means we end up here
  497. // again and repost WM_QUIT+ScheduleWork() again, etc.). Not leaving a
  498. // kMsgHaveWork message behind however is also problematic as unwinding
  499. // multiple layers of nested ::GetMessage() loops can result in starving
  500. // application tasks. TODO(https://crbug.com/890016) : Fix this.
  501. // The return value is mostly irrelevant but return true like we would after
  502. // processing a QuitClosure() task.
  503. return true;
  504. } else if (msg.message == WM_TIMER &&
  505. msg.wParam == reinterpret_cast<UINT_PTR>(this)) {
  506. // This happens when a native nested loop invokes HandleWorkMessage() =>
  507. // ProcessPumpReplacementMessage() which finds the WM_TIMER message
  508. // installed by ScheduleNativeTimer(). That message needs to be handled
  509. // directly as handing it off to ProcessMessageHelper() below would cause an
  510. // unnecessary ScopedDoWorkItem which may incorrectly lead the Delegate's
  511. // heuristics to conclude that the DoWork() in HandleTimerMessage() is
  512. // nested inside a native work item. It's also safe to skip the below
  513. // ScheduleWork() as it is not mandatory before invoking DoWork() and
  514. // HandleTimerMessage() handles re-installing the necessary followup
  515. // messages.
  516. HandleTimerMessage();
  517. return true;
  518. }
  519. // Guarantee we'll get another time slice in the case where we go into native
  520. // windows code. This ScheduleWork() may hurt performance a tiny bit when
  521. // tasks appear very infrequently, but when the event queue is busy, the
  522. // kMsgHaveWork events get (percentage wise) rarer and rarer.
  523. ScheduleWork();
  524. return ProcessMessageHelper(msg);
  525. }
  526. //-----------------------------------------------------------------------------
  527. // MessagePumpForIO public:
  528. MessagePumpForIO::IOContext::IOContext() {
  529. memset(&overlapped, 0, sizeof(overlapped));
  530. }
  531. MessagePumpForIO::IOHandler::IOHandler(const Location& from_here)
  532. : io_handler_location_(from_here) {}
  533. MessagePumpForIO::IOHandler::~IOHandler() = default;
  534. MessagePumpForIO::MessagePumpForIO() {
  535. port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr,
  536. reinterpret_cast<ULONG_PTR>(nullptr), 1));
  537. DCHECK(port_.is_valid());
  538. }
  539. MessagePumpForIO::~MessagePumpForIO() = default;
  540. void MessagePumpForIO::ScheduleWork() {
  541. // This is the only MessagePumpForIO method which can be called outside of
  542. // |bound_thread_|.
  543. bool not_scheduled = false;
  544. if (!work_scheduled_.compare_exchange_strong(not_scheduled, true))
  545. return; // Someone else continued the pumping.
  546. // Make sure the MessagePump does some work for us.
  547. const BOOL ret = ::PostQueuedCompletionStatus(
  548. port_.get(), 0, reinterpret_cast<ULONG_PTR>(this),
  549. reinterpret_cast<OVERLAPPED*>(this));
  550. if (ret)
  551. return; // Post worked perfectly.
  552. // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
  553. work_scheduled_ = false; // Clarify that we didn't succeed.
  554. UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
  555. MESSAGE_LOOP_PROBLEM_MAX);
  556. TRACE_EVENT_INSTANT0("base",
  557. "Chrome.MessageLoopProblem.COMPLETION_POST_ERROR",
  558. TRACE_EVENT_SCOPE_THREAD);
  559. }
  560. void MessagePumpForIO::ScheduleDelayedWork(
  561. const Delegate::NextWorkInfo& next_work_info) {
  562. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  563. // Since this is always called from |bound_thread_|, there is nothing to do as
  564. // the loop is already running. It will WaitForWork() in
  565. // DoRunLoop() with the correct timeout when it's out of immediate tasks.
  566. }
  567. HRESULT MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
  568. IOHandler* handler) {
  569. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  570. HANDLE port = ::CreateIoCompletionPort(
  571. file_handle, port_.get(), reinterpret_cast<ULONG_PTR>(handler), 1);
  572. return (port != nullptr) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
  573. }
  574. bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle,
  575. IOHandler* handler) {
  576. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  577. JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
  578. info.CompletionKey = handler;
  579. info.CompletionPort = port_.get();
  580. return ::SetInformationJobObject(job_handle,
  581. JobObjectAssociateCompletionPortInformation,
  582. &info, sizeof(info)) != FALSE;
  583. }
  584. //-----------------------------------------------------------------------------
  585. // MessagePumpForIO private:
  586. void MessagePumpForIO::DoRunLoop() {
  587. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  588. for (;;) {
  589. // If we do any work, we may create more messages etc., and more work may
  590. // possibly be waiting in another task group. When we (for example)
  591. // WaitForIOCompletion(), there is a good chance there are still more
  592. // messages waiting. On the other hand, when any of these methods return
  593. // having done no work, then it is pretty unlikely that calling them
  594. // again quickly will find any work to do. Finally, if they all say they
  595. // had no work, then it is a good time to consider sleeping (waiting) for
  596. // more work.
  597. Delegate::NextWorkInfo next_work_info = run_state_->delegate->DoWork();
  598. bool more_work_is_plausible = next_work_info.is_immediate();
  599. if (run_state_->should_quit)
  600. break;
  601. run_state_->delegate->BeforeWait();
  602. more_work_is_plausible |= WaitForIOCompletion(0);
  603. if (run_state_->should_quit)
  604. break;
  605. if (more_work_is_plausible)
  606. continue;
  607. more_work_is_plausible = run_state_->delegate->DoIdleWork();
  608. if (run_state_->should_quit)
  609. break;
  610. if (more_work_is_plausible)
  611. continue;
  612. run_state_->delegate->BeforeWait();
  613. WaitForWork(next_work_info);
  614. }
  615. }
  616. // Wait until IO completes, up to the time needed by the timer manager to fire
  617. // the next set of timers.
  618. void MessagePumpForIO::WaitForWork(Delegate::NextWorkInfo next_work_info) {
  619. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  620. // We do not support nested IO message loops. This is to avoid messy
  621. // recursion problems.
  622. DCHECK(!run_state_->is_nested) << "Cannot nest an IO message loop!";
  623. DWORD timeout = GetSleepTimeoutMs(next_work_info.delayed_run_time,
  624. next_work_info.recent_now);
  625. // Tell the optimizer to retain these values to simplify analyzing hangs.
  626. base::debug::Alias(&timeout);
  627. WaitForIOCompletion(timeout);
  628. }
  629. bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout) {
  630. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  631. IOItem item;
  632. if (!GetIOItem(timeout, &item))
  633. return false;
  634. if (ProcessInternalIOItem(item))
  635. return true;
  636. auto scoped_do_work_item = run_state_->delegate->BeginWorkItem();
  637. TRACE_EVENT(
  638. "base,toplevel", "IOHandler::OnIOCompleted",
  639. [&](perfetto::EventContext ctx) {
  640. ctx.event()->set_chrome_message_pump()->set_io_handler_location_iid(
  641. base::trace_event::InternedSourceLocation::Get(
  642. &ctx, base::trace_event::TraceSourceLocation(
  643. item.handler->io_handler_location())));
  644. });
  645. item.handler->OnIOCompleted(item.context, item.bytes_transfered, item.error);
  646. return true;
  647. }
  648. // Asks the OS for another IO completion result.
  649. bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
  650. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  651. memset(item, 0, sizeof(*item));
  652. ULONG_PTR key = reinterpret_cast<ULONG_PTR>(nullptr);
  653. OVERLAPPED* overlapped = nullptr;
  654. if (!::GetQueuedCompletionStatus(port_.get(), &item->bytes_transfered, &key,
  655. &overlapped, timeout)) {
  656. if (!overlapped)
  657. return false; // Nothing in the queue.
  658. item->error = GetLastError();
  659. item->bytes_transfered = 0;
  660. }
  661. item->handler = reinterpret_cast<IOHandler*>(key);
  662. item->context = reinterpret_cast<IOContext*>(overlapped);
  663. return true;
  664. }
  665. bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
  666. DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
  667. if (reinterpret_cast<void*>(this) ==
  668. reinterpret_cast<void*>(item.context.get()) &&
  669. reinterpret_cast<void*>(this) ==
  670. reinterpret_cast<void*>(item.handler.get())) {
  671. // This is our internal completion.
  672. DCHECK(!item.bytes_transfered);
  673. work_scheduled_ = false;
  674. return true;
  675. }
  676. return false;
  677. }
  678. } // namespace base