OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 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 | |
5 #include "mojo/common/message_pump_mojo.h" | |
6 | |
7 #include <algorithm> | |
8 #include <vector> | |
9 | |
10 #include "base/logging.h" | |
11 #include "mojo/common/message_pump_mojo_handler.h" | |
12 #include "mojo/common/scoped_message_pipe.h" | |
13 | |
14 namespace mojo { | |
15 namespace common { | |
16 | |
17 // State needed for one iteration of MojoWaitMany. The first handle and flags | |
18 // corresponds to that of the control pipe. | |
19 struct MessagePumpMojo::WaitState { | |
20 std::vector<MojoHandle> handles; | |
21 std::vector<MojoWaitFlags> wait_flags; | |
22 }; | |
23 | |
24 struct MessagePumpMojo::RunState { | |
25 public: | |
26 RunState() : should_quit(false) {} | |
27 | |
28 MojoHandle read_handle() const { return control_pipe.handle_0(); } | |
29 MojoHandle write_handle() const { return control_pipe.handle_1(); } | |
30 | |
31 base::TimeTicks delayed_work_time; | |
32 | |
33 // Used to wake up WaitForWork(). | |
34 ScopedMessagePipe control_pipe; | |
35 | |
36 bool should_quit; | |
37 }; | |
38 | |
39 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL) { | |
40 } | |
41 | |
42 MessagePumpMojo::~MessagePumpMojo() { | |
43 } | |
44 | |
45 void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, | |
46 MojoHandle handle, | |
Ben Goodger (Google)
2013/11/08 21:24:35
mojo::Handle, mojo::WriteMessage etc?
| |
47 MojoWaitFlags wait_flags) { | |
48 DCHECK(handler); | |
49 DCHECK_NE(MOJO_HANDLE_INVALID, handle); | |
50 handlers_[handle].handler = handler; | |
51 handlers_[handle].wait_flags = wait_flags; | |
52 | |
53 SignalControlPipe(); | |
54 } | |
55 | |
56 void MessagePumpMojo::RemoveHandler(MojoHandle handle) { | |
57 handlers_.erase(handle); | |
58 SignalControlPipe(); | |
59 } | |
60 | |
61 void MessagePumpMojo::Run(Delegate* delegate) { | |
62 RunState* old_state = run_state_; | |
63 RunState run_state; | |
64 // TODO: better deal with error handling. | |
65 CHECK_NE(run_state.control_pipe.handle_0(), MOJO_HANDLE_INVALID); | |
66 CHECK_NE(run_state.control_pipe.handle_1(), MOJO_HANDLE_INVALID); | |
67 run_state_ = &run_state; | |
68 bool more_work_is_plausible = true; | |
69 for (;;) { | |
70 const bool block = !more_work_is_plausible; | |
71 DoInternalWork(block); | |
72 | |
73 // There isn't a good way to know if there are more handles ready, we assume | |
74 // not. | |
75 more_work_is_plausible = false; | |
76 | |
77 if (run_state.should_quit) | |
78 break; | |
79 | |
80 more_work_is_plausible |= delegate->DoWork(); | |
81 if (run_state.should_quit) | |
82 break; | |
83 | |
84 more_work_is_plausible |= delegate->DoDelayedWork( | |
85 &run_state.delayed_work_time); | |
86 if (run_state.should_quit) | |
87 break; | |
88 | |
89 if (more_work_is_plausible) | |
90 continue; | |
91 | |
92 more_work_is_plausible = delegate->DoIdleWork(); | |
93 if (run_state.should_quit) | |
94 break; | |
95 } | |
96 run_state_ = old_state; | |
97 } | |
98 | |
99 void MessagePumpMojo::Quit() { | |
100 if (run_state_) | |
101 run_state_->should_quit = true; | |
102 } | |
103 | |
104 void MessagePumpMojo::ScheduleWork() { | |
105 SignalControlPipe(); | |
106 } | |
107 | |
108 void MessagePumpMojo::ScheduleDelayedWork( | |
109 const base::TimeTicks& delayed_work_time) { | |
110 if (!run_state_) | |
111 return; | |
112 run_state_->delayed_work_time = delayed_work_time; | |
113 SignalControlPipe(); | |
114 } | |
115 | |
116 void MessagePumpMojo::DoInternalWork(bool block) { | |
117 MojoDeadline deadline; | |
118 if (block && !run_state_->delayed_work_time.is_null()) { | |
119 const base::TimeDelta delta = run_state_->delayed_work_time - | |
120 base::TimeTicks::Now(); | |
121 deadline = std::max(static_cast<MojoDeadline>(0), | |
122 static_cast<MojoDeadline>(delta.InMicroseconds())); | |
123 } else { | |
124 deadline = 0; | |
125 } | |
126 const WaitState wait_state = GetWaitState(); | |
127 const MojoResult result = MojoWaitMany(&wait_state.handles.front(), | |
128 &wait_state.wait_flags.front(), | |
129 wait_state.handles.size(), | |
darin (slow to review)
2013/11/09 00:47:50
nit: win64 build will complain here. need static_c
sky
2013/11/11 15:14:17
Done.
| |
130 deadline); | |
131 if (result == 0) { | |
132 // Control pipe was written to. | |
133 uint32_t num_bytes = 0; | |
134 MojoReadMessage(run_state_->read_handle(), NULL, &num_bytes, NULL, 0, | |
135 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | |
136 } else if (result > 0) { | |
137 const size_t index = static_cast<size_t>(result); | |
138 DCHECK(handlers_.find(wait_state.handles[index]) != handlers_.end()); | |
139 handlers_[wait_state.handles[index]].handler->OnHandleReady( | |
140 wait_state.handles[index]); | |
141 } else { | |
142 switch (result) { | |
143 case MOJO_RESULT_INVALID_ARGUMENT: | |
144 case MOJO_RESULT_FAILED_PRECONDITION: | |
145 RemoveFirstInvalidHandle(wait_state); | |
146 break; | |
147 case MOJO_RESULT_DEADLINE_EXCEEDED: | |
148 break; | |
149 default: | |
150 NOTREACHED(); | |
151 } | |
152 } | |
153 } | |
154 | |
155 void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { | |
156 // TODO(sky): deal with control pipe going bad. | |
157 for (size_t i = 1; i < wait_state.handles.size(); ++i) { | |
158 const MojoResult result = | |
159 MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); | |
160 if (result == MOJO_RESULT_INVALID_ARGUMENT || | |
161 result == MOJO_RESULT_FAILED_PRECONDITION) { | |
162 DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); | |
163 MessagePumpMojoHandler* handler = | |
164 handlers_[wait_state.handles[i]].handler; | |
165 handlers_.erase(wait_state.handles[i]); | |
166 handler->OnHandleInvalid(wait_state.handles[i], result); | |
167 return; | |
168 } else { | |
169 DCHECK_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); | |
170 } | |
171 } | |
172 } | |
173 | |
174 void MessagePumpMojo::SignalControlPipe() { | |
175 if (!run_state_) | |
176 return; | |
177 | |
178 // TODO(sky): deal with error? | |
179 MojoWriteMessage(run_state_->write_handle(), NULL, 0, NULL, 0, | |
180 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
181 } | |
182 | |
183 MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState() const { | |
184 WaitState wait_state; | |
185 wait_state.handles.push_back(run_state_->write_handle()); | |
186 wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE); | |
187 | |
188 for (HandleToHandler::const_iterator i = handlers_.begin(); | |
189 i != handlers_.end(); ++i) { | |
190 wait_state.handles.push_back(i->first); | |
191 wait_state.wait_flags.push_back(i->second.wait_flags); | |
192 } | |
193 return wait_state; | |
194 } | |
195 | |
196 } // namespace common | |
197 } // namespace mojo | |
OLD | NEW |