1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2013 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/message_pump/message_pump_mojo.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <algorithm>
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <map>
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <vector>
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/containers/small_map.h"
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/debug/alias.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/lazy_instance.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/logging.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/threading/thread_local.h"
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/threading/thread_restrictions.h"
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/time/time.h"
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/message_pump/message_pump_mojo_handler.h"
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/message_pump/time_helper.h"
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/c/system/wait_set.h"
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace common {
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace {
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbase::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    g_tls_current_pump = LAZY_INSTANCE_INITIALIZER;
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMojoDeadline TimeTicksToMojoDeadline(base::TimeTicks time_ticks,
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                     base::TimeTicks now) {
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The is_null() check matches that of HandleWatcher as well as how
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // |delayed_work_time| is used.
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (time_ticks.is_null())
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return MOJO_DEADLINE_INDEFINITE;
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const int64_t delta = (time_ticks - now).InMicroseconds();
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return delta < 0 ? static_cast<MojoDeadline>(0) :
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                     static_cast<MojoDeadline>(delta);
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct MessagePumpMojo::RunState {
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  RunState() : should_quit(false) {}
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::TimeTicks delayed_work_time;
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool should_quit;
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMessagePumpMojo::MessagePumpMojo()
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : run_state_(NULL),
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      next_handler_id_(0),
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez             base::WaitableEvent::InitialState::NOT_SIGNALED) {
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(!current())
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      << "There is already a MessagePumpMojo instance on this thread.";
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  g_tls_current_pump.Pointer()->Set(this);
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoResult result = CreateMessagePipe(nullptr, &read_handle_, &write_handle_);
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(result, MOJO_RESULT_OK);
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(read_handle_.is_valid());
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(write_handle_.is_valid());
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoHandle handle;
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  result = MojoCreateWaitSet(&handle);
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(result, MOJO_RESULT_OK);
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  wait_set_handle_.reset(Handle(handle));
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(wait_set_handle_.is_valid());
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  result =
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      MojoAddHandle(wait_set_handle_.get().value(), read_handle_.get().value(),
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    MOJO_HANDLE_SIGNAL_READABLE);
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(result, MOJO_RESULT_OK);
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMessagePumpMojo::~MessagePumpMojo() {
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK_EQ(this, current());
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  g_tls_current_pump.Pointer()->Set(NULL);
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// static
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstd::unique_ptr<base::MessagePump> MessagePumpMojo::Create() {
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return std::unique_ptr<MessagePump>(new MessagePumpMojo());
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// static
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMessagePumpMojo* MessagePumpMojo::current() {
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return g_tls_current_pump.Pointer()->Get();
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler,
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                 const Handle& handle,
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                 MojoHandleSignals wait_signals,
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                 base::TimeTicks deadline) {
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(handler);
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(handle.is_valid());
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Assume it's an error if someone tries to reregister an existing handle.
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(0u, handlers_.count(handle));
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  Handler handler_data;
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler_data.handler = handler;
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler_data.wait_signals = wait_signals;
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler_data.deadline = deadline;
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler_data.id = next_handler_id_++;
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handlers_[handle] = handler_data;
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!deadline.is_null()) {
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    bool inserted = deadline_handles_.insert(handle).second;
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(inserted);
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoResult result = MojoAddHandle(wait_set_handle_.get().value(),
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                    handle.value(), wait_signals);
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Because stopping a HandleWatcher is now asynchronous, it's possible for the
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // handle to no longer be open at this point.
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_INVALID_ARGUMENT);
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::RemoveHandler(const Handle& handle) {
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoResult result =
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      MojoRemoveHandle(wait_set_handle_.get().value(), handle.value());
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // At this point, it's possible that the handle has been closed, which would
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // cause MojoRemoveHandle() to return MOJO_RESULT_INVALID_ARGUMENT. It's also
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // possible for the handle to have already been removed, so all of the
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // possible error codes are valid here.
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_NOT_FOUND ||
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        result == MOJO_RESULT_INVALID_ARGUMENT);
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handlers_.erase(handle);
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  deadline_handles_.erase(handle);
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::AddObserver(Observer* observer) {
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  observers_.AddObserver(observer);
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::RemoveObserver(Observer* observer) {
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  observers_.RemoveObserver(observer);
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::Run(Delegate* delegate) {
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  RunState run_state;
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  RunState* old_state = NULL;
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::AutoLock auto_lock(run_state_lock_);
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    old_state = run_state_;
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    run_state_ = &run_state;
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DoRunLoop(&run_state, delegate);
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::AutoLock auto_lock(run_state_lock_);
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    run_state_ = old_state;
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::Quit() {
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock auto_lock(run_state_lock_);
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (run_state_)
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    run_state_->should_quit = true;
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::ScheduleWork() {
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  SignalControlPipe();
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::ScheduleDelayedWork(
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const base::TimeTicks& delayed_work_time) {
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::AutoLock auto_lock(run_state_lock_);
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!run_state_)
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  run_state_->delayed_work_time = delayed_work_time;
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) {
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool more_work_is_plausible = true;
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (;;) {
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const bool block = !more_work_is_plausible;
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (read_handle_.is_valid()) {
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      more_work_is_plausible = DoInternalWork(*run_state, block);
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else {
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      more_work_is_plausible = DoNonMojoWork(*run_state, block);
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (run_state->should_quit)
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    more_work_is_plausible |= delegate->DoWork();
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (run_state->should_quit)
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    more_work_is_plausible |= delegate->DoDelayedWork(
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        &run_state->delayed_work_time);
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (run_state->should_quit)
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (more_work_is_plausible)
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    more_work_is_plausible = delegate->DoIdleWork();
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (run_state->should_quit)
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      break;
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) {
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool did_work = block;
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (block) {
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // If the wait isn't blocking (deadline == 0), there's no point in waiting.
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Wait sets do not require a wait operation to be performed in order to
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // retreive any ready handles. Performing a wait with deadline == 0 is
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // unnecessary work.
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    did_work = WaitForReadyHandles(run_state);
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  did_work |= ProcessReadyHandles();
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  did_work |= RemoveExpiredHandles();
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return did_work;
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MessagePumpMojo::DoNonMojoWork(const RunState& run_state, bool block) {
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool did_work = block;
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (block) {
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const MojoDeadline deadline = GetDeadlineForWait(run_state);
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Stolen from base/message_loop/message_pump_default.cc
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    base::ThreadRestrictions::ScopedAllowWait allow_wait;
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (deadline == MOJO_DEADLINE_INDEFINITE) {
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      event_.Wait();
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    } else {
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      if (deadline > 0) {
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        event_.TimedWait(base::TimeDelta::FromMicroseconds(deadline));
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      } else {
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        did_work = false;
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      }
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Since event_ is auto-reset, we don't need to do anything special here
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // other than service each delegate method.
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  did_work |= RemoveExpiredHandles();
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return did_work;
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MessagePumpMojo::WaitForReadyHandles(const RunState& run_state) const {
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const MojoDeadline deadline = GetDeadlineForWait(run_state);
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const MojoResult wait_result = Wait(
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      wait_set_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, deadline, nullptr);
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (wait_result == MOJO_RESULT_OK) {
250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Handles may be ready. Or not since wake-ups can be spurious in certain
251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // circumstances.
252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return true;
253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  } else if (wait_result == MOJO_RESULT_DEADLINE_EXCEEDED) {
254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::debug::Alias(&wait_result);
258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Unexpected result is likely fatal, crash so we can determine cause.
259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(false);
260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return false;
261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MessagePumpMojo::ProcessReadyHandles() {
264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Maximum number of handles to retrieve and process. Experimentally, the 95th
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // percentile is 1 handle, and the long-term average is 1.1. However, this has
266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // been seen to reach >10 under heavy load. 8 is a hand-wavy compromise.
267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const uint32_t kMaxServiced = 8;
268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t num_ready_handles = kMaxServiced;
269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoHandle handles[kMaxServiced];
270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoResult handle_results[kMaxServiced];
271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const MojoResult get_result =
273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      MojoGetReadyHandles(wait_set_handle_.get().value(), &num_ready_handles,
274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                          handles, handle_results, nullptr);
275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(get_result == MOJO_RESULT_OK || get_result == MOJO_RESULT_SHOULD_WAIT);
276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (get_result != MOJO_RESULT_OK)
277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return false;
278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(num_ready_handles);
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK_LE(num_ready_handles, kMaxServiced);
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Do this in two steps, because notifying a handler may remove/add other
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // handles that may have also been woken up.
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // First, enumerate the IDs of the ready handles. Then, iterate over the
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // handles and only take action if the ID hasn't changed.
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Since the size of this map is bounded by |kMaxServiced|, use a SmallMap to
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // avoid the per-element allocation.
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  base::SmallMap<std::map<Handle, int>, kMaxServiced> ready_handles;
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (uint32_t i = 0; i < num_ready_handles; i++) {
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const Handle handle = Handle(handles[i]);
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Skip the control handle. It's special.
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (handle.value() == read_handle_.get().value())
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(handle.is_valid());
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const auto it = handlers_.find(handle);
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Skip handles that have been removed. This is possible because
296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // RemoveHandler() can be called with a handle that has been closed. Because
297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // the handle is closed, the MojoRemoveHandle() call in RemoveHandler()
298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // would have failed, but the handle is still in the wait set. Once the
299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // handle is retrieved using MojoGetReadyHandles(), it is implicitly removed
300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // from the set. The result is either the pending result that existed when
301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // the handle was closed, or |MOJO_RESULT_CANCELLED| to indicate that the
302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // handle was closed.
303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (it == handlers_.end())
304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ready_handles[handle] = it->second.id;
306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (uint32_t i = 0; i < num_ready_handles; i++) {
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const Handle handle = Handle(handles[i]);
310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // If the handle has been removed, or it's ID has changed, skip over it.
312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // If the handle's ID has changed, and it still satisfies its signals,
313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // then it'll be caught in the next message pump iteration.
314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const auto it = handlers_.find(handle);
315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if ((handle.value() != read_handle_.get().value()) &&
316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        (it == handlers_.end() || it->second.id != ready_handles[handle])) {
317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    switch (handle_results[i]) {
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      case MOJO_RESULT_CANCELLED:
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      case MOJO_RESULT_FAILED_PRECONDITION:
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        DVLOG(1) << "Error: " << handle_results[i]
324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                 << " handle: " << handle.value();
325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (handle.value() == read_handle_.get().value()) {
326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // The Mojo EDK is shutting down. We can't just quit the message pump
327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // because that may cause the thread to quit, which causes the
328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // thread's MessageLoop to be destroyed, which races with any use of
329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // |Thread::task_runner()|. So instead, we enter a "dumb" mode which
330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // bypasses Mojo and just acts like a trivial message pump. That way,
331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // we can wait for the usual thread exiting mechanism to happen.
332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // The dumb mode is indicated by releasing the control pipe's read
333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // handle.
334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          read_handle_.reset();
335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        } else {
336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          SignalHandleError(handle, handle_results[i]);
337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        break;
339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      case MOJO_RESULT_OK:
340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if (handle.value() == read_handle_.get().value()) {
341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          DVLOG(1) << "Signaled control pipe";
342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          // Control pipe was written to.
343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          ReadMessageRaw(read_handle_.get(), nullptr, nullptr, nullptr, nullptr,
344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                         MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        } else {
346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          DVLOG(1) << "Handle ready: " << handle.value();
347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez          SignalHandleReady(handle);
348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        }
349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        break;
350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      default:
351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        base::debug::Alias(&i);
352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        base::debug::Alias(&handle_results[i]);
353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        // Unexpected result is likely fatal, crash so we can determine cause.
354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        CHECK(false);
355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return true;
358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezbool MessagePumpMojo::RemoveExpiredHandles() {
361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  bool removed = false;
362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Notify and remove any handlers whose time has expired. First, iterate over
363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // the set of handles that have a deadline, and add the expired handles to a
364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // map of <Handle, id>. Then, iterate over those expired handles and remove
365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // them. The two-step process is because a handler can add/remove new
366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // handlers.
367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  std::map<Handle, int> expired_handles;
368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const base::TimeTicks now(internal::NowTicks());
369645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (const Handle handle : deadline_handles_) {
370645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const auto it = handlers_.find(handle);
371645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Expect any handle in |deadline_handles_| to also be in |handlers_| since
372645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // the two are modified in lock-step.
373645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(it != handlers_.end());
374645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (!it->second.deadline.is_null() && it->second.deadline < now)
375645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      expired_handles[handle] = it->second.id;
376645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
377645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (const auto& pair : expired_handles) {
378645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    auto it = handlers_.find(pair.first);
379645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Don't need to check deadline again since it can't change if id hasn't
380645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // changed.
381645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (it != handlers_.end() && it->second.id == pair.second) {
382645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      SignalHandleError(pair.first, MOJO_RESULT_DEADLINE_EXCEEDED);
383645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      removed = true;
384645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
385645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
386645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return removed;
387645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
388645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
389645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::SignalControlPipe() {
390645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const MojoResult result =
391645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      WriteMessageRaw(write_handle_.get(), NULL, 0, NULL, 0,
392645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                      MOJO_WRITE_MESSAGE_FLAG_NONE);
393645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (result == MOJO_RESULT_FAILED_PRECONDITION) {
394645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    // Mojo EDK is shutting down.
395645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    event_.Signal();
396645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
397645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
398645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
399645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // If we can't write we likely won't wake up the thread and there is a strong
400645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // chance we'll deadlock.
401645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(MOJO_RESULT_OK, result);
402645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
403645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
404645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMojoDeadline MessagePumpMojo::GetDeadlineForWait(
405645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const RunState& run_state) const {
406645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const base::TimeTicks now(internal::NowTicks());
407645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time,
408645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                                  now);
409645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (const Handle handle : deadline_handles_) {
410645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    auto it = handlers_.find(handle);
411645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DCHECK(it != handlers_.end());
412645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    deadline = std::min(
413645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        TimeTicksToMojoDeadline(it->second.deadline, now), deadline);
414645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
415645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return deadline;
416645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
417645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
418645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::SignalHandleReady(Handle handle) {
419645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  auto it = handlers_.find(handle);
420645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(it != handlers_.end());
421645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MessagePumpMojoHandler* handler = it->second.handler;
422645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
423645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  WillSignalHandler();
424645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler->OnHandleReady(handle);
425645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DidSignalHandler();
426645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
427645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
428645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::SignalHandleError(Handle handle, MojoResult result) {
429645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  auto it = handlers_.find(handle);
430645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DCHECK(it != handlers_.end());
431645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MessagePumpMojoHandler* handler = it->second.handler;
432645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
433645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  RemoveHandler(handle);
434645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  WillSignalHandler();
435645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handler->OnHandleError(handle, result);
436645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DidSignalHandler();
437645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
438645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
439645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::WillSignalHandler() {
440645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler());
441645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
442645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
443645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid MessagePumpMojo::DidSignalHandler() {
444645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler());
445645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
446645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
447645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace common
448645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
449