OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/common/message_pump_mojo.h" | 5 #include "mojo/common/message_pump_mojo.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 27 matching lines...) Expand all Loading... | |
38 }; | 38 }; |
39 | 39 |
40 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL) { | 40 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL) { |
41 } | 41 } |
42 | 42 |
43 MessagePumpMojo::~MessagePumpMojo() { | 43 MessagePumpMojo::~MessagePumpMojo() { |
44 } | 44 } |
45 | 45 |
46 void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, | 46 void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, |
47 MojoHandle handle, | 47 MojoHandle handle, |
48 MojoWaitFlags wait_flags) { | 48 MojoWaitFlags wait_flags, |
49 base::TimeTicks deadline) { | |
49 DCHECK(handler); | 50 DCHECK(handler); |
50 DCHECK_NE(MOJO_HANDLE_INVALID, handle); | 51 DCHECK_NE(MOJO_HANDLE_INVALID, handle); |
51 handlers_[handle].handler = handler; | 52 // Assume it's an error if someone tries to reregister an existing handle. |
52 handlers_[handle].wait_flags = wait_flags; | 53 DCHECK_EQ(0u, handlers_.count(handle)); |
53 | 54 Handler handler_data; |
54 SignalControlPipe(); | 55 handler_data.handler = handler; |
56 handler_data.wait_flags = wait_flags; | |
57 handler_data.deadline = deadline; | |
58 handlers_[handle] = handler_data; | |
55 } | 59 } |
56 | 60 |
57 void MessagePumpMojo::RemoveHandler(MojoHandle handle) { | 61 void MessagePumpMojo::RemoveHandler(MojoHandle handle) { |
58 handlers_.erase(handle); | 62 handlers_.erase(handle); |
59 SignalControlPipe(); | |
60 } | 63 } |
61 | 64 |
62 void MessagePumpMojo::Run(Delegate* delegate) { | 65 void MessagePumpMojo::Run(Delegate* delegate) { |
63 RunState* old_state = run_state_; | 66 RunState* old_state = run_state_; |
64 RunState run_state; | 67 RunState run_state; |
65 // TODO: better deal with error handling. | 68 // TODO: better deal with error handling. |
66 CHECK_NE(run_state.control_pipe.handle_0(), MOJO_HANDLE_INVALID); | 69 CHECK_NE(run_state.control_pipe.handle_0(), MOJO_HANDLE_INVALID); |
67 CHECK_NE(run_state.control_pipe.handle_1(), MOJO_HANDLE_INVALID); | 70 CHECK_NE(run_state.control_pipe.handle_1(), MOJO_HANDLE_INVALID); |
68 run_state_ = &run_state; | 71 run_state_ = &run_state; |
69 bool more_work_is_plausible = true; | 72 bool more_work_is_plausible = true; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 | 111 |
109 void MessagePumpMojo::ScheduleDelayedWork( | 112 void MessagePumpMojo::ScheduleDelayedWork( |
110 const base::TimeTicks& delayed_work_time) { | 113 const base::TimeTicks& delayed_work_time) { |
111 if (!run_state_) | 114 if (!run_state_) |
112 return; | 115 return; |
113 run_state_->delayed_work_time = delayed_work_time; | 116 run_state_->delayed_work_time = delayed_work_time; |
114 SignalControlPipe(); | 117 SignalControlPipe(); |
115 } | 118 } |
116 | 119 |
117 void MessagePumpMojo::DoInternalWork(bool block) { | 120 void MessagePumpMojo::DoInternalWork(bool block) { |
118 MojoDeadline deadline; | 121 const MojoDeadline deadline = block ? GetDeadlineForWait() : 0; |
119 if (block && !run_state_->delayed_work_time.is_null()) { | |
120 const base::TimeDelta delta = run_state_->delayed_work_time - | |
121 base::TimeTicks::Now(); | |
122 deadline = std::max(static_cast<MojoDeadline>(0), | |
123 static_cast<MojoDeadline>(delta.InMicroseconds())); | |
124 } else { | |
125 deadline = 0; | |
126 } | |
127 const WaitState wait_state = GetWaitState(); | 122 const WaitState wait_state = GetWaitState(); |
128 const MojoResult result = MojoWaitMany( | 123 const MojoResult result = MojoWaitMany( |
129 &wait_state.handles.front(), | 124 &wait_state.handles.front(), |
130 &wait_state.wait_flags.front(), | 125 &wait_state.wait_flags.front(), |
131 static_cast<uint32_t>(wait_state.handles.size()), | 126 static_cast<uint32_t>(wait_state.handles.size()), |
132 deadline); | 127 deadline); |
133 if (result == 0) { | 128 if (result == 0) { |
134 // Control pipe was written to. | 129 // Control pipe was written to. |
135 uint32_t num_bytes = 0; | 130 uint32_t num_bytes = 0; |
136 MojoReadMessage(run_state_->read_handle(), NULL, &num_bytes, NULL, 0, | 131 MojoReadMessage(run_state_->read_handle(), NULL, &num_bytes, NULL, 0, |
137 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | 132 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
138 } else if (result > 0) { | 133 } else if (result > 0) { |
139 const size_t index = static_cast<size_t>(result); | 134 const size_t index = static_cast<size_t>(result); |
140 DCHECK(handlers_.find(wait_state.handles[index]) != handlers_.end()); | 135 DCHECK(handlers_.find(wait_state.handles[index]) != handlers_.end()); |
141 handlers_[wait_state.handles[index]].handler->OnHandleReady( | 136 handlers_[wait_state.handles[index]].handler->OnHandleReady( |
142 wait_state.handles[index]); | 137 wait_state.handles[index]); |
143 } else { | 138 } else { |
144 switch (result) { | 139 switch (result) { |
145 case MOJO_RESULT_INVALID_ARGUMENT: | 140 case MOJO_RESULT_INVALID_ARGUMENT: |
146 case MOJO_RESULT_FAILED_PRECONDITION: | 141 case MOJO_RESULT_FAILED_PRECONDITION: |
147 RemoveFirstInvalidHandle(wait_state); | 142 RemoveFirstInvalidHandle(wait_state); |
148 break; | 143 break; |
149 case MOJO_RESULT_DEADLINE_EXCEEDED: | 144 case MOJO_RESULT_DEADLINE_EXCEEDED: |
150 break; | 145 break; |
151 default: | 146 default: |
152 NOTREACHED(); | 147 NOTREACHED(); |
153 } | 148 } |
154 } | 149 } |
150 | |
151 // Notify and remove any handlers whose time has expired. Make a copy in case | |
152 // someone tries to add/remove new handlers from notification. | |
153 const HandleToHandler cloned_handlers(handlers_); | |
154 const base::TimeTicks now(base::TimeTicks::Now()); | |
155 for (HandleToHandler::const_iterator i = cloned_handlers.begin(); | |
156 i != cloned_handlers.end(); ++i) { | |
157 // Since we're iterating over a clone of the handlers, verify the handler is | |
158 // still valid before notifying. | |
159 if (!i->second.deadline.is_null() && i->second.deadline < now && | |
160 handlers_.find(i->first) != handlers_.end() && | |
darin (slow to review)
2013/11/22 23:03:32
I think there could be subtle bugs here with the h
sky
2013/11/22 23:25:25
I went with an id for equality.
| |
161 i->second.handler == handlers_[i->first].handler) { | |
162 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); | |
163 } | |
164 } | |
155 } | 165 } |
156 | 166 |
157 void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { | 167 void MessagePumpMojo::RemoveFirstInvalidHandle(const WaitState& wait_state) { |
158 // TODO(sky): deal with control pipe going bad. | 168 // TODO(sky): deal with control pipe going bad. |
159 for (size_t i = 1; i < wait_state.handles.size(); ++i) { | 169 for (size_t i = 1; i < wait_state.handles.size(); ++i) { |
160 const MojoResult result = | 170 const MojoResult result = |
161 MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); | 171 MojoWait(wait_state.handles[i], wait_state.wait_flags[i], 0); |
162 if (result == MOJO_RESULT_INVALID_ARGUMENT || | 172 if (result == MOJO_RESULT_INVALID_ARGUMENT || |
163 result == MOJO_RESULT_FAILED_PRECONDITION) { | 173 result == MOJO_RESULT_FAILED_PRECONDITION) { |
174 // Remove the handle first, this way if OnHandleError() tries to remove | |
175 // the handle our iterator isn't invalidated. | |
164 DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); | 176 DCHECK(handlers_.find(wait_state.handles[i]) != handlers_.end()); |
165 MessagePumpMojoHandler* handler = | 177 MessagePumpMojoHandler* handler = |
166 handlers_[wait_state.handles[i]].handler; | 178 handlers_[wait_state.handles[i]].handler; |
167 handlers_.erase(wait_state.handles[i]); | 179 handlers_.erase(wait_state.handles[i]); |
168 handler->OnHandleError(wait_state.handles[i], result); | 180 handler->OnHandleError(wait_state.handles[i], result); |
169 return; | 181 return; |
170 } else { | 182 } else { |
171 DCHECK_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); | 183 DCHECK_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); |
172 } | 184 } |
173 } | 185 } |
(...skipping 14 matching lines...) Expand all Loading... | |
188 wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE); | 200 wait_state.wait_flags.push_back(MOJO_WAIT_FLAG_READABLE); |
189 | 201 |
190 for (HandleToHandler::const_iterator i = handlers_.begin(); | 202 for (HandleToHandler::const_iterator i = handlers_.begin(); |
191 i != handlers_.end(); ++i) { | 203 i != handlers_.end(); ++i) { |
192 wait_state.handles.push_back(i->first); | 204 wait_state.handles.push_back(i->first); |
193 wait_state.wait_flags.push_back(i->second.wait_flags); | 205 wait_state.wait_flags.push_back(i->second.wait_flags); |
194 } | 206 } |
195 return wait_state; | 207 return wait_state; |
196 } | 208 } |
197 | 209 |
210 MojoDeadline MessagePumpMojo::GetDeadlineForWait() const { | |
211 base::TimeTicks min_time = run_state_->delayed_work_time; | |
212 for (HandleToHandler::const_iterator i = handlers_.begin(); | |
213 i != handlers_.end(); ++i) { | |
214 if (min_time.is_null() && i->second.deadline < min_time) | |
215 min_time = i->second.deadline; | |
216 } | |
217 return min_time.is_null() ? MOJO_DEADLINE_INDEFINITE : | |
218 std::max(static_cast<MojoDeadline>(0), | |
219 static_cast<MojoDeadline>( | |
220 (min_time - base::TimeTicks::Now()).InMicroseconds())); | |
221 } | |
222 | |
198 } // namespace common | 223 } // namespace common |
199 } // namespace mojo | 224 } // namespace mojo |
OLD | NEW |